1    | /***************************************
2    |   $Header: /cvsroot/petscgraphics/geomview.c,v 1.6 2003/04/30 19:34:55 hazelsct Exp $
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   | 
14   | /* Build with -DDEBUG for debugging output */
15   | #undef DPRINTF
16   | #ifdef DEBUG
17   | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args)
18   | #else
19   | #define DPRINTF(fmt, args...)
20   | #endif
21   | 
22   | /*+ Stream holding the pipe to the Geomview process.  It is initialized to
23   |   NULL, then set by GeomviewBegin, and cleared by GeomviewEnd.  This can be
24   |   used as a flag to determine whether the Geomview display is open. +*/
25   | static FILE *pfd = NULL;
26   | 
27   | /*+ Declared in illuminator.c, this gives the current number of triangles on
28   |   this node. +*/
29   | extern int num_triangles;
30   | 
31   | /*+ Declared in illuminator.c, this array stores the corner coordinates and
32   |   color information for each triangle. +*/
33   | extern PetscScalar vertices[];
34   | 
35   | 
36   | #undef __FUNCT__
37   | #define __FUNCT__ "GeomviewBegin"
38   | 
39   | /*++++++++++++++++++++++++++++++++++++++
40   |   Spawn a new geomview process.  Most of this was shamelessly ripped from Ken
41   |   Brakke's Surface Evolver.
42   | 
43   |   int GeomviewBegin Returns 0 or an error code.
44   | 
45   |   MPI_Comm comm MPI communicator for rank information, if NULL it uses
46   |   PETSC_COMM_WORLD.
47   |   ++++++++++++++++++++++++++++++++++++++*/
48   | 
49   | int GeomviewBegin(MPI_Comm comm)
50   | {
51   |   int rank, ierr, gv_pid,gv_pipe[2], to_gv_pipe[2];
52   |   char gv_version[100];
53   | 
54   |   if (!comm)
55   |     comm = PETSC_COMM_WORLD;
56   |   ierr = MPI_Comm_rank (comm,&rank); CHKERRQ(ierr);
57   |   if (!rank)
58   |     {
59   |       if (pfd)
60   | 	SETERRQ (PETSC_ERR_ARG_WRONGSTATE,
61   | 		 "Multiple geomview displays not allowed");
62   | 
63   |       pipe (gv_pipe); /* from geomview stdout */
64   |       pipe (to_gv_pipe); /* to geomview stdin */
65   |       gv_pid = fork ();
66   | 
67   |       if(gv_pid==0) /* child */
68   | 	{
69   | 	  close (0);
70   | 	  dup (to_gv_pipe[0]);
71   | 	  close (to_gv_pipe[0]);
72   | 	  close (to_gv_pipe[1]);
73   | 	  close (1);
74   | 	  dup (gv_pipe[1]);
75   | 	  close (gv_pipe[0]);
76   | 	  close (gv_pipe[1]);
77   | 	  /* signal(SIGINT,SIG_IGN); */
78   | 	  execlp (GEOMVIEW,GEOMVIEW,"-c","(interest (pick world))","-",NULL);
79   | 	  perror (GEOMVIEW); /* only error gets here */
80   | 	  SETERRQ (PETSC_ERR_ARG_WRONGSTATE,"Geomview invocation failed.\n");
81   | 	}
82   | 
83   |       /* PETSc program execution resumes here */
84   |       close (gv_pipe[1]);
85   |       close (to_gv_pipe[0]);
86   |       pfd = fdopen (to_gv_pipe[1], "w"); /* hooked to stdin of geomview */
87   |       fprintf (pfd, "(echo (geomview-version) \"\n\")\n");
88   |       fflush (pfd);
89   |       read (gv_pipe[0], gv_version, sizeof (gv_version));
90   |     }
91   |   return 0;
92   | }
93   | 
94   | 
95   | #undef __FUNCT__
96   | #define __FUNCT__ "GeomviewEnd"
97   | 
98   | /*++++++++++++++++++++++++++++++++++++++
99   |   Exit the current running Geomview process and close its pipe.  Based in part
100  |   on Ken Brakke's Surface Evolver.
101  | 
102  |   int GeomviewEnd Returns 0 or an error code.
103  | 
104  |   MPI_Comm comm MPI communicator for rank information, if NULL it uses
105  |   PETSC_COMM_WORLD.
106  |   ++++++++++++++++++++++++++++++++++++++*/
107  | 
108  | int GeomviewEnd (MPI_Comm comm)
109  | {
110  |   int rank, ierr;
111  | 
112  |   if (!comm)
113  |     comm = PETSC_COMM_WORLD;
114  |   ierr = MPI_Comm_rank (comm, &rank); CHKERRQ (ierr);
115  |   if (!rank)
116  |     {
117  |       if (pfd)
118  | 	{
119  | 	  fprintf (pfd, "(exit)");
120  | 	  fclose (pfd);
121  | 	  pfd = NULL;
122  | 	}
123  |     }
124  |   return 0;
125  | }
126  | 
127  | 
128  | #undef __FUNCT__
129  | #define __FUNCT__ "GeomviewDisplayTriangulation"
130  | 
131  | /*++++++++++++++++++++++++++++++++++++++
132  |   Pipe the current triangulation to Geomview for display.  Much of this is
133  |   based on Ken Brakke's Surface Evolver.
134  | 
135  |   int GeomviewDisplayTriangulation Returns 0 or an error code.
136  | 
137  |   MPI_Comm comm MPI communicator for rank information, if NULL it uses
138  |   PETSC_COMM_WORLD.
139  | 
140  |   PetscScalar *minmax Position of block corners: xmin, xmax, ymin, ymax, zmin, zmax.
141  | 
142  |   char *name Name to give the Geomview OOGL object which we create.
143  | 
144  |   PetscTruth transparent Geomview transparency flag.
145  |   ++++++++++++++++++++++++++++++++++++++*/
146  | 
147  | int GeomviewDisplayTriangulation
148  | (MPI_Comm comm, PetscScalar *minmax, char *name, PetscTruth transparent)
149  | {
150  |   int ierr, i, total_entries, start, end, rank;
151  |   PetscScalar *localvals;
152  |   Vec globalverts, localverts;
153  |   VecScatter vecscat;
154  |   IS islocal;
155  | 
156  |   /* Simple "assertion" check */
157  |   if (!comm)
158  |     comm = PETSC_COMM_WORLD;
159  |   ierr = MPI_Comm_rank (comm, &rank); CHKERRQ (ierr);
160  |   if (!rank && !pfd)
161  |     SETERRQ (PETSC_ERR_ARG_WRONGSTATE,"Geomview display is not open!");
162  | 
163  |   /*+ First, this creates global and local vectors for all of the triangle
164  |     vertices. +*/
165  |   ierr = VecCreateMPIWithArray (comm, 13*num_triangles, PETSC_DETERMINE,
166  | 				vertices, &globalverts); CHKERRQ (ierr);
167  |   ierr = VecGetSize (globalverts, &total_entries); CHKERRQ (ierr);
168  |   ierr = VecCreateMPI (comm, (rank == 0) ? total_entries:0, total_entries,
169  | 		       &localverts); CHKERRQ (ierr);
170  |   DPRINTF ("Total triangles: %d\n", total_entries/13);
171  | 
172  |   /* Diagnostics which may be useful to somebody sometime */
173  |   /* ierr = VecGetOwnershipRange (globalverts, &start, &end); CHKERRQ (ierr);
174  |   ierr = PetscSynchronizedPrintf
175  |     (comm, "[%d] Global vector local size: %d, ownership from %d to %d\n",
176  |      rank, end-start, start, end); CHKERRQ (ierr);
177  |   ierr = PetscSynchronizedFlush (comm); CHKERRQ (ierr);
178  | 
179  |   ierr = VecGetOwnershipRange (localverts, &start, &end); CHKERRQ (ierr);
180  |   ierr = PetscSynchronizedPrintf
181  |     (comm, "[%d] Local vector local size: %d, ownership from %d to %d\n", rank,
182  |      end-start, start, end); CHKERRQ (ierr);
183  |   ierr = PetscSynchronizedFlush (comm); CHKERRQ (ierr);
184  |   ierr = PetscPrintf (comm, "Global vector size: %d\n", total_entries);
185  |   CHKERRQ (ierr); */
186  | 
187  |   /*+ It then gathers (``scatters'') all vertex data to processor zero, +*/
188  |   ierr = ISCreateStride (comm, total_entries, 0, 1, &islocal); CHKERRQ (ierr);
189  |   ierr = VecScatterCreate (globalverts, PETSC_NULL, localverts, islocal,
190  | 			   &vecscat); CHKERRQ (ierr);
191  |   DPRINTF ("Starting triangle scatter to head node\n",0);
192  |   ierr = VecScatterBegin (globalverts, localverts, INSERT_VALUES,
193  | 			  SCATTER_FORWARD, vecscat); CHKERRQ (ierr);
194  |   DPRINTF ("Triangle scatter to head node in progress...\n",0);
195  |   ierr = VecScatterEnd (globalverts, localverts, INSERT_VALUES,
196  | 			SCATTER_FORWARD, vecscat); CHKERRQ (ierr);
197  |   DPRINTF ("Triangle scatter to head node complete\n",0);
198  |   ierr = VecScatterDestroy (vecscat); CHKERRQ (ierr);
199  |   ierr = ISDestroy (islocal); CHKERRQ (ierr);
200  | 
201  |   /*+ and puts them in an array. +*/
202  |   ierr = VecGetArray (localverts, &localvals); CHKERRQ (ierr);
203  | 
204  |   /*+ Finally, it sends everything to Geomview, +*/
205  |   if (!rank) {
206  |     fprintf (pfd, "(geometry \"%s\" { : bor })", name);
207  |     fprintf (pfd, "(read geometry { define bor \n");
208  |     fprintf (pfd, "appearance {%s}\nOFF\n", transparent ? "+transparent" : "");
209  |     fprintf (pfd, "%d %d 0\n", 3*(total_entries/13) + 2, total_entries/13);
210  |     for (i=0; i<total_entries; i+=13)
211  |       fprintf (pfd, "%g %g %g\n%g %g %g\n%g %g %g\n", localvals[i],
212  | 	       localvals[i+1], localvals[i+2], localvals[i+3], localvals[i+4],
213  | 	       localvals[i+5], localvals[i+6], localvals[i+7], localvals[i+8]);
214  |     fprintf (pfd, "%g %g %g\n%g %g %g\n", minmax[0], minmax[2], minmax[4],
215  | 	     minmax[1], minmax[3], minmax[5]);
216  |     for (i=0; i<total_entries/13; i++)
217  |       fprintf (pfd, "3 %d %d %d %g %g %g %g\n", 3*i,3*i+1,3*i+2,
218  | 	       localvals[13*i+9], localvals[13*i+10], localvals[13*i+11],
219  | 	       localvals[13*i+12]);
220  |     fprintf (pfd, "})\n");
221  |     fflush (pfd);
222  |   }
223  | 
224  |   /*+ and cleans up the mess, resetting the number of triangles to zero. +*/
225  |   ierr = VecRestoreArray (localverts, &localvals); CHKERRQ (ierr);
226  |   ierr = VecDestroy (localverts); CHKERRQ (ierr);
227  |   ierr = VecDestroy (globalverts); CHKERRQ (ierr);
228  |   num_triangles = 0;
229  | 
230  |   return 0;
231  | }