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