1 | /*************************************** 2 | $Header$ 3 | 4 | This file has the Geomview interface, including the PETSc vector gather 5 | operations to bring everything to CPU 0. 6 | ***************************************/ 7 | 8 | 9 | #include <stdio.h> 10 | #include <petscvec.h> 11 | #include "config.h" /* esp. for inline */ 12 | #include "illuminator.h" /* Just to make sure the interface is "right" */ 13 | #include "structures.h" /* For isurface structure definition */ 14 | #include <stdlib.h> /* For malloc() */ 15 | #include <unistd.h> /* For execlp() */ 16 | #include <glib.h> /* For guint*, GUINT*_SWAP_LE_BE */ 17 | 18 | /* Build with -DDEBUG for debugging output */ 19 | #undef DPRINTF 20 | #ifdef DEBUG 21 | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args) 22 | #else 23 | #define DPRINTF(fmt, args...) 24 | #endif 25 | 26 | 27 | #undef __FUNCT__ 28 | #define __FUNCT__ "GeomviewBegin" 29 | 30 | /*++++++++++++++++++++++++++++++++++++++ 31 | Spawn a new geomview process. Most of this was shamelessly ripped from Ken 32 | Brakke's Surface Evolver. 33 | 34 | int GeomviewBegin Returns 0 or an error code. 35 | 36 | MPI_Comm comm MPI communicator for rank information, if NULL it uses 37 | PETSC_COMM_WORLD. 38 | 39 | IDisplay *newdisp Pointer in which to put a new IDisplay object. 40 | ++++++++++++++++++++++++++++++++++++++*/ 41 | 42 | int GeomviewBegin(MPI_Comm comm, IDisplay *newdisp) 43 | { 44 | int rank, ierr, gv_pid,gv_pipe[2], to_gv_pipe[2]; 45 | char gv_version[100]; 46 | struct idisplay *thedisp; 47 | 48 | if (!(thedisp = (struct idisplay *) malloc (sizeof (struct idisplay)))) 49 | SETERRQ (PETSC_ERR_MEM, "Unable to allocate memory for isurface object"); 50 | 51 | /* Initialize display image to zero */ 52 | thedisp->rgb = NULL; 53 | thedisp->rgb_width = thedisp->rgb_height = thedisp->rgb_rowskip = 54 | thedisp->rgb_bpp = 0; 55 | thedisp->zbuf = NULL; 56 | thedisp->zbuf_width = thedisp->zbuf_height = thedisp->zbuf_depth = 57 | thedisp->zbuf_rowskip = 0; 58 | 59 | if (!comm) 60 | comm = PETSC_COMM_WORLD; 61 | ierr = MPI_Comm_rank (comm,&rank); CHKERRQ(ierr); 62 | if (!rank) 63 | { 64 | pipe (gv_pipe); /* from geomview stdout */ 65 | pipe (to_gv_pipe); /* to geomview stdin */ 66 | gv_pid = fork (); 67 | 68 | if(gv_pid==0) /* child */ 69 | { 70 | close (0); 71 | dup (to_gv_pipe[0]); 72 | close (to_gv_pipe[0]); 73 | close (to_gv_pipe[1]); 74 | close (1); 75 | dup (gv_pipe[1]); 76 | close (gv_pipe[0]); 77 | close (gv_pipe[1]); 78 | /* signal(SIGINT,SIG_IGN); */ 79 | execlp (GEOMVIEW,GEOMVIEW,"-c","(interest (pick world))","-",NULL); 80 | perror (GEOMVIEW); /* only error gets here */ 81 | SETERRQ (PETSC_ERR_ARG_WRONGSTATE,"Geomview invocation failed.\n"); 82 | } 83 | 84 | /* PETSc program execution resumes here */ 85 | close (gv_pipe[1]); 86 | close (to_gv_pipe[0]); 87 | thedisp->to_geomview = fdopen (to_gv_pipe[1], "w"); /* geomview stdin */ 88 | fprintf (thedisp->to_geomview, "(echo (geomview-version) \"\n\")\n"); 89 | fflush (thedisp->to_geomview); 90 | read (gv_pipe[0], gv_version, sizeof (gv_version)); 91 | } 92 | 93 | *newdisp = (IDisplay) thedisp; 94 | return 0; 95 | } 96 | 97 | 98 | #undef __FUNCT__ 99 | #define __FUNCT__ "GeomviewEnd" 100 | 101 | /*++++++++++++++++++++++++++++++++++++++ 102 | Exit the current running Geomview process and close its pipe. Based in part 103 | on Ken Brakke's Surface Evolver. 104 | 105 | int GeomviewEnd Returns 0 or an error code. 106 | 107 | MPI_Comm comm MPI communicator for rank information, if NULL it uses 108 | PETSC_COMM_WORLD. 109 | 110 | IDisplay Disp IDisplay object whose geomview FILE we're closing. 111 | ++++++++++++++++++++++++++++++++++++++*/ 112 | 113 | int GeomviewEnd (MPI_Comm comm, IDisplay Disp) 114 | { 115 | int rank, ierr; 116 | struct idisplay *thedisp = (struct idisplay *) Disp; 117 | 118 | if (!comm) 119 | comm = PETSC_COMM_WORLD; 120 | ierr = MPI_Comm_rank (comm, &rank); CHKERRQ (ierr); 121 | if (!rank) 122 | { 123 | if (thedisp->to_geomview) 124 | { 125 | fprintf (thedisp->to_geomview, "(exit)"); 126 | fclose (thedisp->to_geomview); 127 | thedisp->to_geomview = NULL; 128 | } 129 | } 130 | return 0; 131 | } 132 | 133 | 134 | #ifdef WORDS_BIGENDIAN 135 | # define GEOMVIEW_SET_INT(j,x) gvint[j]=(guint32)(x) 136 | # define GEOMVIEW_SET_FLOAT(j,x) gvfloat[j]=(float)(x) 137 | #else 138 | # define GEOMVIEW_SET_INT(j,x) \ 139 | gvint[j]=GUINT32_SWAP_LE_BE_CONSTANT((guint32) (x)) 140 | # define GEOMVIEW_SET_FLOAT(j,x) \ 141 | {gvfloat[j]=(float)(x); gvint[j]=GUINT32_SWAP_LE_BE_CONSTANT(gvint[j]);} 142 | #endif 143 | 144 | /* #define GEOMVIEW_BINARY */ 145 | 146 | 147 | #undef __FUNCT__ 148 | #define __FUNCT__ "GeomviewDisplayTriangulation" 149 | 150 | /*++++++++++++++++++++++++++++++++++++++ 151 | Pipe the current triangulation to Geomview for display. Much of this is 152 | based on Ken Brakke's Surface Evolver. 153 | 154 | int GeomviewDisplayTriangulation Returns 0 or an error code. 155 | 156 | MPI_Comm comm MPI communicator for rank information, if NULL it uses 157 | PETSC_COMM_WORLD. 158 | 159 | ISurface Surf ISurface object containing triangles to render using Geomview. 160 | 161 | IDisplay Disp IDisplay object whose geomview FILE we're closing. 162 | 163 | PetscScalar *minmax Position of block corners: xmin, xmax, ymin, ymax, zmin, zmax. 164 | 165 | char *name Name to give the Geomview OOGL object which we create. 166 | 167 | PetscTruth transparent Geomview transparency flag. 168 | ++++++++++++++++++++++++++++++++++++++*/ 169 | 170 | int GeomviewDisplayTriangulation 171 | (MPI_Comm comm, ISurface Surf, IDisplay Disp, PetscScalar *minmax, char *name, 172 | PetscTruth transparent) 173 | { 174 | int ierr, i, total_entries, start, end, rank; 175 | PetscScalar *localvals; 176 | Vec globalverts, localverts; 177 | VecScatter vecscat; 178 | IS islocal; 179 | struct isurface *thesurf = (struct isurface *) Surf; 180 | struct idisplay *thedisp = (struct idisplay *) Disp; 181 | 182 | /* Simple "assertion" check */ 183 | if (!comm) 184 | comm = PETSC_COMM_WORLD; 185 | ierr = MPI_Comm_rank (comm, &rank); CHKERRQ (ierr); 186 | if (!rank && !thedisp->to_geomview) 187 | SETERRQ (PETSC_ERR_ARG_WRONGSTATE,"Geomview display is not open!"); 188 | 189 | /*+ First, this creates global and local vectors for all of the triangle 190 | vertices. +*/ 191 | ierr = VecCreateMPIWithArray (comm, 13*thesurf->num_triangles, 192 | PETSC_DETERMINE, 193 | thesurf->vertices, &globalverts); CHKERRQ (ierr); 194 | ierr = VecGetSize (globalverts, &total_entries); CHKERRQ (ierr); 195 | ierr = VecCreateMPI (comm, (rank == 0) ? total_entries:0, total_entries, 196 | &localverts); CHKERRQ (ierr); 197 | DPRINTF ("Total triangles: %d\n", total_entries/13); 198 | 199 | /* Diagnostics which may be useful to somebody sometime */ 200 | /* ierr = VecGetOwnershipRange (globalverts, &start, &end); CHKERRQ (ierr); 201 | ierr = PetscSynchronizedPrintf 202 | (comm, "[%d] Global vector local size: %d, ownership from %d to %d\n", 203 | rank, end-start, start, end); CHKERRQ (ierr); 204 | ierr = PetscSynchronizedFlush (comm); CHKERRQ (ierr); 205 | 206 | ierr = VecGetOwnershipRange (localverts, &start, &end); CHKERRQ (ierr); 207 | ierr = PetscSynchronizedPrintf 208 | (comm, "[%d] Local vector local size: %d, ownership from %d to %d\n", rank, 209 | end-start, start, end); CHKERRQ (ierr); 210 | ierr = PetscSynchronizedFlush (comm); CHKERRQ (ierr); 211 | ierr = PetscPrintf (comm, "Global vector size: %d\n", total_entries); 212 | CHKERRQ (ierr); */ 213 | 214 | /*+ It then gathers (``scatters'') all vertex data to processor zero, +*/ 215 | ierr = ISCreateStride (comm, total_entries, 0, 1, &islocal); CHKERRQ (ierr); 216 | ierr = VecScatterCreate (globalverts, PETSC_NULL, localverts, islocal, 217 | &vecscat); CHKERRQ (ierr); 218 | DPRINTF ("Starting triangle scatter to head node\n",0); 219 | ierr = VecScatterBegin (vecscat, globalverts, localverts, INSERT_VALUES, 220 | SCATTER_FORWARD); CHKERRQ (ierr); 221 | DPRINTF ("Triangle scatter to head node in progress...\n",0); 222 | ierr = VecScatterEnd (vecscat, globalverts, localverts, INSERT_VALUES, 223 | SCATTER_FORWARD); CHKERRQ (ierr); 224 | DPRINTF ("Triangle scatter to head node complete\n",0); 225 | ierr = VecScatterDestroy (vecscat); CHKERRQ (ierr); 226 | ierr = ISDestroy (islocal); CHKERRQ (ierr); 227 | 228 | /*+ and puts them in an array. +*/ 229 | ierr = VecGetArray (localverts, &localvals); CHKERRQ (ierr); 230 | 231 | /*+ Finally, it sends everything to Geomview, +*/ 232 | if (!rank) { 233 | #ifdef GEOMVIEW_BINARY 234 | guint32 gvint[10]; 235 | float *gvfloat = (float *)gvint; 236 | #endif 237 | 238 | fprintf (thedisp->to_geomview, "(geometry \"%s\" { : bor })", name); 239 | fprintf (thedisp->to_geomview, "(read geometry { define bor \n"); 240 | fprintf (thedisp->to_geomview, "appearance {%s}\nOFF%s\n", 241 | transparent ? "+transparent" : "", 242 | #ifdef GEOMVIEW_BINARY 243 | " BINARY" 244 | #else 245 | "" 246 | #endif 247 | ); 248 | #ifndef GEOMVIEW_BINARY 249 | fprintf (thedisp->to_geomview, "%d %d 0\n", 3*(total_entries/13) + 2, 250 | total_entries/13); 251 | #else 252 | GEOMVIEW_SET_INT (0, 3*(total_entries/13) + 2); 253 | GEOMVIEW_SET_INT (1, total_entries/13); 254 | GEOMVIEW_SET_INT (2, 0); 255 | fwrite (gvint, sizeof (guint32), 3, thedisp->to_geomview); 256 | #endif 257 | for (i=0; i<total_entries; i+=13) 258 | { 259 | #ifndef GEOMVIEW_BINARY 260 | fprintf (thedisp->to_geomview, "%g %g %g\n%g %g %g\n%g %g %g\n", 261 | localvals[i], localvals[i+1], localvals[i+2], localvals[i+3], 262 | localvals[i+4], localvals[i+5], localvals[i+6],localvals[i+7], 263 | localvals[i+8]); 264 | #else 265 | GEOMVIEW_SET_FLOAT(0, localvals[i]); 266 | GEOMVIEW_SET_FLOAT(1, localvals[i+1]); 267 | GEOMVIEW_SET_FLOAT(2, localvals[i+2]); 268 | GEOMVIEW_SET_FLOAT(3, localvals[i+3]); 269 | GEOMVIEW_SET_FLOAT(4, localvals[i+4]); 270 | GEOMVIEW_SET_FLOAT(5, localvals[i+5]); 271 | GEOMVIEW_SET_FLOAT(6, localvals[i+6]); 272 | GEOMVIEW_SET_FLOAT(7, localvals[i+7]); 273 | GEOMVIEW_SET_FLOAT(8, localvals[i+8]); 274 | fwrite (gvfloat, sizeof (float), 9, thedisp->to_geomview); 275 | #endif 276 | } 277 | #ifndef GEOMVIEW_BINARY 278 | fprintf (thedisp->to_geomview, "%g %g %g\n%g %g %g\n", minmax[0],minmax[2], 279 | minmax[4], minmax[1], minmax[3], minmax[5]); 280 | #else 281 | GEOMVIEW_SET_FLOAT(0, minmax[0]); 282 | GEOMVIEW_SET_FLOAT(1, minmax[2]); 283 | GEOMVIEW_SET_FLOAT(2, minmax[4]); 284 | GEOMVIEW_SET_FLOAT(3, minmax[1]); 285 | GEOMVIEW_SET_FLOAT(4, minmax[3]); 286 | GEOMVIEW_SET_FLOAT(5, minmax[5]); 287 | fwrite (gvfloat, sizeof (float), 6, thedisp->to_geomview); 288 | #endif 289 | for (i=0; i<total_entries/13; i++) 290 | { 291 | #ifndef GEOMVIEW_BINARY 292 | fprintf (thedisp->to_geomview,"3 %d %d %d %g %g %g %g\n", 293 | 3*i, 3*i+1, 3*i+2, 294 | localvals[13*i+9], localvals[13*i+10], localvals[13*i+11], 295 | localvals[13*i+12]); 296 | #else 297 | GEOMVIEW_SET_INT(0, 3); 298 | GEOMVIEW_SET_INT(1, 3*i); 299 | GEOMVIEW_SET_INT(2, 3*i+1); 300 | GEOMVIEW_SET_INT(3, 3*i+2); 301 | GEOMVIEW_SET_INT(4, 4); 302 | fwrite (gvint, sizeof (guint32), 5, thedisp->to_geomview); 303 | GEOMVIEW_SET_FLOAT(0, localvals[13*i+9]); 304 | GEOMVIEW_SET_FLOAT(1, localvals[13*i+10]); 305 | GEOMVIEW_SET_FLOAT(2, localvals[13*i+11]); 306 | GEOMVIEW_SET_FLOAT(3, localvals[13*i+12]); 307 | fwrite (gvfloat, sizeof (float), 4, thedisp->to_geomview); 308 | #endif 309 | } 310 | fprintf (thedisp->to_geomview, "})\n"); 311 | fflush (thedisp->to_geomview); 312 | } 313 | 314 | /*+ and cleans up the mess. +*/ 315 | ierr = VecRestoreArray (localverts, &localvals); CHKERRQ (ierr); 316 | ierr = VecDestroy (localverts); CHKERRQ (ierr); 317 | ierr = VecDestroy (globalverts); CHKERRQ (ierr); 318 | 319 | return 0; 320 | }