1 | /***************************************
2 | $Header: /cvsroot/petscgraphics/tsview-ng.c,v 1.21 2004/08/11 12:44:08 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, current_field, *field_index, num_variables[1],
57 | **variable_indices;
58 |
59 | /* First some primary functions which do stuff, then callbacks, then main(). */
60 |
61 | #undef __FUNCT__
62 | #define __FUNCT__ "render_dataviews"
63 |
64 | void render_dataviews ()
65 | {
66 | int viewnum, nx,ny,nz, ierr;
67 |
68 | DPRINTF ("Rendering dataviews\n",0);
69 | if (dataview_count != 1)
70 | {
71 | printf ("dataview_count != 1 is not yet supported\n");
72 | exit(0);
73 | }
74 | for (viewnum=0; viewnum<dataview_count; viewnum++)
75 | {
76 | int nx,ny, xs,ys, xm,ym, ix,iy;
77 | PetscScalar minval, maxval, refmag, *global_array;
78 | GtkType type;
79 | char thestatus [100];
80 |
81 | /* (Re)allocate buffer */
82 | DPRINTF ("(Re)allocating RGB buffer\n",0);
83 | if (!(rgbbuf [viewnum] =
84 | (guchar *) realloc (rgbbuf [viewnum],
85 | 3*width*height*sizeof(guchar)))) {
86 | printf ("ERROR: can't reallocate RGB buffer\n");
87 | exit (1); }
88 |
89 | /* Render into rgbbuf [viewnum] */
90 | ierr = DAGetInfo (theda, PETSC_NULL, &nx,&ny,PETSC_NULL,
91 | PETSC_NULL,PETSC_NULL,PETSC_NULL, PETSC_NULL,
92 | PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
93 | ierr = DAGetCorners (theda, &xs,&ys,PETSC_NULL, &xm,&ym,PETSC_NULL);
94 | CHKERRQ (ierr);
95 | ierr = VecGetArray (global, &global_array); CHKERRQ (ierr);
96 | ierr = render_rgb_local_2d
97 | (rgbbuf [viewnum], width,height, 3, global_array, num_fields,
98 | current_field, fieldtypes [current_field],
99 | ((fieldtypes [current_field] == FIELD_VECTOR ||
100 | fieldtypes [current_field] == FIELD_VECTOR) &&
101 | vecmax > 0) ? (&vecmax)-1 : NULL, nx,ny, xs,ys, xm,ym);
102 | ierr = VecRestoreArray (global, &global_array); CHKERRQ (ierr);
103 |
104 | /* Draw buffer onto window */
105 | DPRINTF ("Painting rgb buffer onto window\n",0);
106 | if (!dataviews [viewnum])
107 | dataviews [viewnum] = glade_xml_get_widget (xml, "plot_area");
108 | gtk_drawing_area_size (GTK_DRAWING_AREA (dataviews [viewnum]),
109 | width, height);
110 | gdk_draw_rgb_image (dataviews [viewnum]->window,
111 | dataviews [viewnum]->style->fg_gc[GTK_STATE_NORMAL],
112 | 0, 0, width, height, GDK_RGB_DITHER_MAX,
113 | rgbbuf [viewnum], width * 3);
114 | }
115 | }
116 |
117 |
118 | #undef __FUNCT__
119 | #define __FUNCT__ "myfilter"
120 |
121 | /*+ Little variable for myfilter() and refresh_stepnames(). +*/
122 | static char *basefilename;
123 |
124 | /*++++++++++++++++++++++++++++++++++++++
125 | This function returns non-zero for "qualifying" file names which start with
126 | the stored files' basename.time and end with
127 | +latex+{\tt .cpu0000.meta}.
128 | +html+ <tt>.cpu0000.meta</tt>.
129 | It is used as the
130 | +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}.
131 | +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>.
132 |
133 | int myfilter Returns non-zero for qualifying filenames.
134 |
135 | const struct dirent *direntry Directory entry with filename to test.
136 | ++++++++++++++++++++++++++++++++++++++*/
137 |
138 | int myfilter (const struct dirent *direntry)
139 | {
140 | if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename))) &&
141 | (!strncmp (direntry->d_name + strlen(basefilename), ".time", 5)))
142 | return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13,
143 | ".cpu0000.meta", 13));
144 | return 0;
145 | }
146 |
147 |
148 | void on_plot_area_expose_event (GtkWidget *widget, GdkEventExpose *event,
149 | gpointer user_data)
150 | {
151 | gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
152 | 0, 0, width, height, GDK_RGB_DITHER_MAX, rgbbuf [0],
153 | width * 3);
154 | }
155 |
156 | /*++++++++++++++++++++++++++++++++++++++
157 | This loads the names of the files into a long list.
158 | ++++++++++++++++++++++++++++++++++++++*/
159 |
160 | int refresh_stepnames ()
161 | {
162 | struct dirent **namelist;
163 | char *filec, *dirc;
164 | int i, ierr;
165 |
166 | filec = strdup (the_basename);
167 | dirc = strdup (the_basename);
168 | basefilename = basename (filec);
169 | basedirname = dirname (dirc);
170 |
171 | total_entries = scandir (basedirname, &namelist, myfilter, alphasort);
172 | if (!total_entries)
173 | {
174 | ierr = PetscPrintf (PETSC_COMM_WORLD, "No such files\n");
175 | CHKERRQ (ierr);
176 | return 1;
177 | }
178 | if (total_entries < 0)
179 | {
180 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n",
181 | basedirname); CHKERRQ (ierr);
182 | ierr = PetscFinalize (); CHKERRQ(ierr);
183 | return 1;
184 | }
185 | DPRINTF ("%d eligible files:\n", total_entries);
186 |
187 | if (!(stepnames = (char **) realloc
188 | (stepnames, total_entries*sizeof (char *))))
189 | {
190 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n");
191 | CHKERRQ (ierr);
192 | return 1;
193 | }
194 | for (i=0; i<total_entries; i++)
195 | {
196 | int filength = strlen(namelist[i]->d_name);
197 |
198 | stepnames [i] = (char *) malloc ((filength-12)*sizeof(char));
199 | strncpy (stepnames [i], namelist[i]->d_name, filength-13);
200 | stepnames [i] [filength-13] = '\0';
201 | free (namelist[i]);
202 | DPRINTF ("[%d] %s\n", i, stepnames [i]);
203 | CHKERRQ (ierr);
204 | }
205 |
206 | free (namelist);
207 | return 0;
208 | }
209 |
210 | void change_variable (GtkWidget *widget, gpointer user_data)
211 | {
212 | current_field = GPOINTER_TO_INT (widget);
213 | DPRINTF ("Switching to variable %d\n", current_field);
214 | render_dataviews();
215 | }
216 |
217 | void on_mag_spin_value_changed (GtkWidget *mag_spin, gpointer user_data) {
218 | G_CONST_RETURN gchar *entrytext;
219 | entrytext = gtk_entry_get_text (GTK_ENTRY (mag_spin));
220 | sscanf (entrytext, "%lf", &sizemag);
221 | width = (int) (minmax [1] * sizemag);
222 | height = (int) (minmax [3] * sizemag);
223 |
224 | render_dataviews();
225 | }
226 |
227 |
228 | void display_timestep (int usermetacount, char **usermetanames,
229 | char **usermetadata)
230 | {
231 | int i;
232 | static char step_buffer [20], time_buffer [20];
233 |
234 | for (i=0; i<usermetacount; i++)
235 | {
236 | if (!strncmp (usermetanames [i], "timestep", 8))
237 | sscanf (usermetadata [i], "%d", ¤t_timestep);
238 | else if (!strncmp (usermetanames [i], "time", 4))
239 | sscanf (usermetadata [i], "%lf", ¤t_time);
240 | }
241 | snprintf (step_buffer, 19, "Timestep: %d", current_timestep);
242 | gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "timestep_label")),
243 | step_buffer);
244 | snprintf (time_buffer, 19, "Time: %g", current_time);
245 | gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "time_label")),
246 | time_buffer);
247 |
248 | on_mag_spin_value_changed (glade_xml_get_widget (xml, "mag_spin"), NULL);
249 | }
250 |
251 |
252 | void on_save_activate (GtkWidget *widget, gpointer user_data)
253 | {
254 | int i, ierr;
255 | char **usermetanames, **usermetadata, filename [200], number[10];
256 | FILE *outppm;
257 |
258 | strncpy (filename, basedirname, 198);
259 | strcat (filename, "/");
260 | strncat (filename, stepnames [entrynum], 198 - strlen (filename));
261 | snprintf (number, 9, "-f%d", current_field);
262 | strncat (filename, number, 198 - strlen (filename));
263 | strncat (filename, ".ppm", 198 - strlen (filename));
264 |
265 | DPRINTF ("Saving image with filename %s\n", filename);
266 | if (!(outppm = fopen (filename, "w")))
267 | printf ("Error opening file %s\n", filename);
268 | fprintf (outppm, "P6\n%d %d\n255\n", width, height);
269 | fwrite (rgbbuf [0], sizeof (guchar), 3*width*height, outppm);
270 | fclose (outppm);
271 | }
272 |
273 |
274 | void on_timestep_spin_value_changed (GtkWidget *timestep_spin, gpointer user_data) {
275 | int usermetacount, ierr;
276 | G_CONST_RETURN gchar *entrytext;
277 | char **usermetanames, **usermetadata, filename [200], **field_name;
278 | GtkWidget *variable_options, *variable_menu, **variable_item;
279 |
280 | entrytext = gtk_entry_get_text (GTK_ENTRY (timestep_spin));
281 | sscanf (entrytext, "%d", &entrynum);
282 |
283 | /* Bound the entrynum between 0 and total_entries-1; -11 is the minimum of
284 | the widget (from jump), 1000001 is the maximum. */
285 | if ((entrynum < 0 && entrynum != -11) || entrynum == 1000001)
286 | entrynum = total_entries-1;
287 | if ((entrynum >= total_entries && entrynum != 1000001) || entrynum == -11)
288 | entrynum = 0;
289 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin),
290 | (gfloat) entrynum);
291 |
292 | strncpy (filename, basedirname, 198);
293 | strcat (filename, "/");
294 | strncat (filename, stepnames [entrynum], 198 - strlen (filename));
295 |
296 | ierr = IlluMultiRead (theda, global, filename, &usermetacount,&usermetanames,
297 | &usermetadata); CHKERRQ (ierr);
298 |
299 | display_timestep (usermetacount, usermetanames, usermetadata);
300 | }
301 |
302 |
303 | void on_refresh_activate (GtkWidget *none, gpointer user_data) {
304 | if (refresh_stepnames ()) exit (1); }
305 |
306 |
307 | void on_about_activate (GtkWidget *none, gpointer user_data) {
308 | gtk_widget_show (glade_xml_get_widget (xml, "about")); }
309 |
310 |
311 | #undef __FUNCT__
312 | #define __FUNCT__ "main"
313 |
314 | /*++++++++++++++++++++++++++++++++++++++
315 | This is
316 | +latex+{\tt main()}.
317 | +html+ <tt>main()</tt>.
318 |
319 | int main It returns an int to the OS.
320 |
321 | int argc Argument count.
322 |
323 | char *argv[] Arguments.
324 | ++++++++++++++++++++++++++++++++++++++*/
325 |
326 | int main (int argc, char *argv[])
327 | {
328 | /* GnomeProgram *app; */
329 | /* struct poptOption options [] = {
330 | { "vector_max", 'vm', POPT_ARG_FLOAT, &vecmax, 0, "Reference vector length", "VECMAX" },
331 | { NULL, '\0', 0, NULL, 0, NULL, NULL }}; */
332 | int usermetacount=0, i, ierr;
333 | char **usermetanames, **usermetadata, filename [200], **field_name;
334 | GtkWidget *variable_options, *variable_menu, **variable_item;
335 |
336 | /*+ After
337 | +latex+{\tt PETSc}
338 | +html+ <tt>PETSc</tt>
339 | and glade/GNOME initialization, it gets the list of files matching the
340 | basename. +*/
341 | ierr = PetscInitialize (&argc, &argv, (char *)0, help); CHKERRQ (ierr);
342 |
343 | if (argc<2)
344 | {
345 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Usage: tsview basename\n");
346 | CHKERRQ (ierr);
347 | return 1;
348 | }
349 |
350 | #ifdef DEBUG
351 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Command line:"); CHKERRQ (ierr);
352 | for (i=0; i<argc; i++)
353 | {
354 | ierr = PetscPrintf (PETSC_COMM_WORLD, " %s", argv[i]); CHKERRQ (ierr);
355 | }
356 | ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr);
357 | #endif
358 |
359 | vecmax = -1.0;
360 | ierr = PetscOptionsGetScalar (PETSC_NULL, "-vector_max", &vecmax,PETSC_NULL);
361 | CHKERRQ (ierr);
362 | ierr = PetscOptionsHasName (PETSC_NULL, "-no_transparency", &transp);
363 | CHKERRQ (ierr);
364 | transp = !transp;
365 |
366 | /* Kludge alert! Setting argc to avoid gnome_program_init errors;
367 | fix: use GNOME arguments instead of PETSc. */
368 | argc=2;
369 |
370 | DPRINTF ("Running gnome_program_init with argc=2\n",0);
371 | gnome_program_init ("TSView", VERSION, LIBGNOMEUI_MODULE, argc, argv, NULL);
372 |
373 | strncpy (filename, GLADE_DIRECTORY, 187);
374 | strcat (filename, "/tsview.glade");
375 | xml = glade_xml_new (filename, NULL, NULL);
376 | glade_xml_signal_autoconnect (xml);
377 |
378 | if (argc>1)
379 | the_basename = argv[1];
380 | else
381 | {
382 | /* Put in filter for .time0000000.cpu0000.meta */
383 | gtk_widget_show (glade_xml_get_widget (xml, "open_fileselect"));
384 | }
385 |
386 | DPRINTF ("Loading list of timestep names\n",0);
387 | if (refresh_stepnames ())
388 | exit (1);
389 |
390 | DPRINTF ("Loading first timestep, creating distributed array\n",0);
391 | strncpy (filename, basedirname, 198);
392 | strcat (filename, "/");
393 | strncat (filename, stepnames [0], 198 - strlen (stepnames [0]));
394 | ierr = IlluMultiLoad (filename, &theda, minmax+1,minmax+3,minmax+5,
395 | &fieldtypes, &usermetacount, &usermetanames,
396 | &usermetadata);
397 | CHKERRQ (ierr);
398 |
399 | /* Usermetadata xwidth, ywidth, zwidth override minmax in case IlluMulti
400 | version of saved data is 0.1. */
401 | DPRINTF ("Checking usermetadata for width information\n",0);
402 | for (i=0; i<usermetacount; i++)
403 | {
404 | if (!strncmp (usermetanames [i], "xwidth", 6))
405 | sscanf (usermetadata [i], "%lf", minmax+1);
406 | else if (!strncmp (usermetanames [i], "ywidth", 6))
407 | sscanf (usermetadata [i], "%lf", minmax+3);
408 | else if (!strncmp (usermetanames [i], "zwidth", 6))
409 | sscanf (usermetadata [i], "%lf", minmax+5);
410 | }
411 |
412 | DPRINTF ("Getting distributed array global vector and info\n",0);
413 | ierr = DAGetGlobalVector (theda, &global); CHKERRQ (ierr);
414 | ierr = DAGetInfo (theda, &dimensions, PETSC_NULL,PETSC_NULL,PETSC_NULL,
415 | PETSC_NULL,PETSC_NULL,PETSC_NULL, &num_fields,
416 | PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
417 | if (dimensions != 2)
418 | SETERRQ (PETSC_ERR_ARG_OUTOFRANGE, "tsview-ng only supports 2-D distributed arrays at this point.");
419 |
420 | /* Build menu of field variables */
421 | variable_options = glade_xml_get_widget (xml, "variable_menu");
422 | gtk_option_menu_remove_menu (GTK_OPTION_MENU (variable_options));
423 | variable_menu = gtk_menu_new ();
424 | variable_item = (GtkWidget **) malloc (num_fields * sizeof (GtkWidget *));
425 | field_name = (char **) malloc (num_fields * sizeof (char *));
426 | field_index = (int *) malloc (num_fields * sizeof (int));
427 | field_indices (num_fields, dimensions, fieldtypes, field_index);
428 | DPRINTF ("Field indices:\n",0);
429 | for (i=0; i<num_fields && field_index [i] != -1; i++)
430 | {
431 | ierr = DAGetFieldName (theda, field_index [i], field_name+i);
432 | CHKERRQ (ierr);
433 | DPRINTF ("%d index %d name %s\n", i, field_index [i], field_name [i]);
434 | variable_item [i] = gtk_menu_item_new_with_label (field_name [i]);
435 | gtk_menu_append (GTK_MENU (variable_menu), variable_item [i]);
436 | gtk_signal_connect_object (GTK_OBJECT (variable_item [i]), "activate",
437 | GTK_SIGNAL_FUNC (change_variable),
438 | GINT_TO_POINTER (field_index [i]));
439 | gtk_widget_show (variable_item [i]);
440 | }
441 | gtk_option_menu_set_menu (GTK_OPTION_MENU (variable_options), variable_menu);
442 | gtk_widget_show (variable_menu);
443 | gtk_widget_show (variable_options);
444 |
445 | /* Main window title */
446 | {
447 | char main_window_title[100] = "TSView: ";
448 | GtkWidget *main_window = glade_xml_get_widget (xml, "main_window");
449 |
450 | strncat (main_window_title, basename (the_basename), 90);
451 | gtk_window_set_title (GTK_WINDOW (main_window), main_window_title);
452 | gtk_widget_show (main_window);
453 | }
454 |
455 | DPRINTF ("Displaying first timestep\n",0);
456 | display_timestep (usermetacount, usermetanames, usermetadata);
457 |
458 | DPRINTF ("Running main loop\n",0);
459 | gtk_main();
460 |
461 | DPRINTF ("Finalizing and exitting.\n",0);
462 | ierr = PetscFinalize (); CHKERRQ(ierr);
463 | return 0;
464 | }