xref: /petsc/src/ksp/pc/impls/tfs/comm.c (revision 0924e98c97c437ba98313834470257b43063364e)
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2827bd09bSSatish Balay 
3827bd09bSSatish Balay /***********************************comm.c*************************************
4827bd09bSSatish Balay 
5827bd09bSSatish Balay Author: Henry M. Tufo III
6827bd09bSSatish Balay 
7827bd09bSSatish Balay e-mail: hmt@cs.brown.edu
8827bd09bSSatish Balay 
9827bd09bSSatish Balay snail-mail:
10827bd09bSSatish Balay Division of Applied Mathematics
11827bd09bSSatish Balay Brown University
12827bd09bSSatish Balay Providence, RI 02912
13827bd09bSSatish Balay 
14827bd09bSSatish Balay Last Modification:
15827bd09bSSatish Balay 11.21.97
16827bd09bSSatish Balay ***********************************comm.c*************************************/
17827bd09bSSatish Balay 
18827bd09bSSatish Balay /***********************************comm.c*************************************
19827bd09bSSatish Balay File Description:
20827bd09bSSatish Balay -----------------
21827bd09bSSatish Balay 
22827bd09bSSatish Balay ***********************************comm.c*************************************/
237758a8cdSBarry Smith #include "src/ksp/pc/impls/tfs/tfs.h"
24827bd09bSSatish Balay 
25827bd09bSSatish Balay 
26827bd09bSSatish Balay /* global program control variables - explicitly exported */
27827bd09bSSatish Balay int my_id            = 0;
28827bd09bSSatish Balay int num_nodes        = 1;
29827bd09bSSatish Balay int floor_num_nodes  = 0;
30827bd09bSSatish Balay int i_log2_num_nodes = 0;
31827bd09bSSatish Balay 
32827bd09bSSatish Balay /* global program control variables */
33827bd09bSSatish Balay static int p_init = 0;
34827bd09bSSatish Balay static int modfl_num_nodes;
35827bd09bSSatish Balay static int edge_not_pow_2;
36827bd09bSSatish Balay 
37a501084fSBarry Smith static unsigned int edge_node[sizeof(PetscInt)*32];
38827bd09bSSatish Balay 
39827bd09bSSatish Balay /***********************************comm.c*************************************
40827bd09bSSatish Balay Function: giop()
41827bd09bSSatish Balay 
42827bd09bSSatish Balay Input :
43827bd09bSSatish Balay Output:
44827bd09bSSatish Balay Return:
45827bd09bSSatish Balay Description:
46827bd09bSSatish Balay ***********************************comm.c*************************************/
47*0924e98cSBarry Smith PetscErrorCode comm_init (void)
48827bd09bSSatish Balay {
49827bd09bSSatish Balay 
503fdc5746SBarry Smith   if (p_init++)   PetscFunctionReturn(0);
51827bd09bSSatish Balay 
52827bd09bSSatish Balay   MPI_Comm_size(MPI_COMM_WORLD,&num_nodes);
53827bd09bSSatish Balay   MPI_Comm_rank(MPI_COMM_WORLD,&my_id);
54827bd09bSSatish Balay 
55827bd09bSSatish Balay   if (num_nodes> (INT_MAX >> 1))
56827bd09bSSatish Balay   {error_msg_fatal("Can't have more then MAX_INT/2 nodes!!!");}
57827bd09bSSatish Balay 
583fdc5746SBarry Smith   ivec_zero((PetscInt*)edge_node,sizeof(PetscInt)*32);
59827bd09bSSatish Balay 
60827bd09bSSatish Balay   floor_num_nodes = 1;
61827bd09bSSatish Balay   i_log2_num_nodes = modfl_num_nodes = 0;
62827bd09bSSatish Balay   while (floor_num_nodes <= num_nodes)
63827bd09bSSatish Balay     {
64827bd09bSSatish Balay       edge_node[i_log2_num_nodes] = my_id ^ floor_num_nodes;
65827bd09bSSatish Balay       floor_num_nodes <<= 1;
66827bd09bSSatish Balay       i_log2_num_nodes++;
67827bd09bSSatish Balay     }
68827bd09bSSatish Balay 
69827bd09bSSatish Balay   i_log2_num_nodes--;
70827bd09bSSatish Balay   floor_num_nodes >>= 1;
71827bd09bSSatish Balay   modfl_num_nodes = (num_nodes - floor_num_nodes);
72827bd09bSSatish Balay 
73827bd09bSSatish Balay   if ((my_id > 0) && (my_id <= modfl_num_nodes))
74827bd09bSSatish Balay     {edge_not_pow_2=((my_id|floor_num_nodes)-1);}
75827bd09bSSatish Balay   else if (my_id >= floor_num_nodes)
76827bd09bSSatish Balay     {edge_not_pow_2=((my_id^floor_num_nodes)+1);
77827bd09bSSatish Balay     }
78827bd09bSSatish Balay   else
79827bd09bSSatish Balay     {edge_not_pow_2 = 0;}
803fdc5746SBarry Smith   PetscFunctionReturn(0);
81827bd09bSSatish Balay }
82827bd09bSSatish Balay 
83827bd09bSSatish Balay 
84827bd09bSSatish Balay 
85827bd09bSSatish Balay /***********************************comm.c*************************************
86827bd09bSSatish Balay Function: giop()
87827bd09bSSatish Balay 
88827bd09bSSatish Balay Input :
89827bd09bSSatish Balay Output:
90827bd09bSSatish Balay Return:
91827bd09bSSatish Balay Description: fan-in/out version
92827bd09bSSatish Balay ***********************************comm.c*************************************/
93*0924e98cSBarry Smith PetscErrorCode giop(PetscInt *vals, PetscInt *work, PetscInt n, PetscInt *oprs)
94827bd09bSSatish Balay {
953fdc5746SBarry Smith    PetscInt mask, edge;
963fdc5746SBarry Smith   PetscInt type, dest;
97827bd09bSSatish Balay   vfp fp;
98827bd09bSSatish Balay   MPI_Status  status;
993fdc5746SBarry Smith   PetscInt ierr;
100827bd09bSSatish Balay 
1013fdc5746SBarry Smith    PetscFunctionBegin;
102827bd09bSSatish Balay   /* ok ... should have some data, work, and operator(s) */
103827bd09bSSatish Balay   if (!vals||!work||!oprs)
10477431f27SBarry Smith     {error_msg_fatal("giop() :: vals=%D, work=%D, oprs=%D",vals,work,oprs);}
105827bd09bSSatish Balay 
106827bd09bSSatish Balay   /* non-uniform should have at least two entries */
107827bd09bSSatish Balay   if ((oprs[0] == NON_UNIFORM)&&(n<2))
108827bd09bSSatish Balay     {error_msg_fatal("giop() :: non_uniform and n=0,1?");}
109827bd09bSSatish Balay 
110827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
111827bd09bSSatish Balay   if (!p_init)
112827bd09bSSatish Balay     {comm_init();}
113827bd09bSSatish Balay 
114827bd09bSSatish Balay   /* if there's nothing to do return */
115827bd09bSSatish Balay   if ((num_nodes<2)||(!n))
116827bd09bSSatish Balay     {
1173fdc5746SBarry Smith         PetscFunctionReturn(0);
118827bd09bSSatish Balay     }
119827bd09bSSatish Balay 
120827bd09bSSatish Balay   /* a negative number if items to send ==> fatal */
121827bd09bSSatish Balay   if (n<0)
12277431f27SBarry Smith     {error_msg_fatal("giop() :: n=%D<0?",n);}
123827bd09bSSatish Balay 
124827bd09bSSatish Balay   /* advance to list of n operations for custom */
125827bd09bSSatish Balay   if ((type=oprs[0])==NON_UNIFORM)
126827bd09bSSatish Balay     {oprs++;}
127827bd09bSSatish Balay 
128827bd09bSSatish Balay   /* major league hack */
129d890fc11SSatish Balay   if (!(fp = (vfp) ivec_fct_addr(type))) {
130827bd09bSSatish Balay     error_msg_warning("giop() :: hope you passed in a rbfp!\n");
131827bd09bSSatish Balay     fp = (vfp) oprs;
132827bd09bSSatish Balay   }
133827bd09bSSatish Balay 
134827bd09bSSatish Balay   /* all msgs will be of the same length */
135827bd09bSSatish Balay   /* if not a hypercube must colapse partial dim */
136827bd09bSSatish Balay   if (edge_not_pow_2)
137827bd09bSSatish Balay     {
138827bd09bSSatish Balay       if (my_id >= floor_num_nodes)
1393fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_INT,edge_not_pow_2,MSGTAG0+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
140827bd09bSSatish Balay       else
141827bd09bSSatish Balay 	{
1423fdc5746SBarry Smith 	  ierr = MPI_Recv(work,n,MPIU_INT,MPI_ANY_SOURCE,MSGTAG0+edge_not_pow_2, MPI_COMM_WORLD,&status);CHKERRQ(ierr);
143827bd09bSSatish Balay 	  (*fp)(vals,work,n,oprs);
144827bd09bSSatish Balay 	}
145827bd09bSSatish Balay     }
146827bd09bSSatish Balay 
147827bd09bSSatish Balay   /* implement the mesh fan in/out exchange algorithm */
148827bd09bSSatish Balay   if (my_id<floor_num_nodes)
149827bd09bSSatish Balay     {
150827bd09bSSatish Balay       for (mask=1,edge=0; edge<i_log2_num_nodes; edge++,mask<<=1)
151827bd09bSSatish Balay 	{
152827bd09bSSatish Balay 	  dest = my_id^mask;
153827bd09bSSatish Balay 	  if (my_id > dest)
1543fdc5746SBarry Smith 	    {ierr = MPI_Send(vals,n,MPIU_INT,dest,MSGTAG2+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
155827bd09bSSatish Balay 	  else
156827bd09bSSatish Balay 	    {
1573fdc5746SBarry Smith 	      ierr = MPI_Recv(work,n,MPIU_INT,MPI_ANY_SOURCE,MSGTAG2+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
158827bd09bSSatish Balay 	      (*fp)(vals, work, n, oprs);
159827bd09bSSatish Balay 	    }
160827bd09bSSatish Balay 	}
161827bd09bSSatish Balay 
162827bd09bSSatish Balay       mask=floor_num_nodes>>1;
163827bd09bSSatish Balay       for (edge=0; edge<i_log2_num_nodes; edge++,mask>>=1)
164827bd09bSSatish Balay 	{
165827bd09bSSatish Balay 	  if (my_id%mask)
166827bd09bSSatish Balay 	    {continue;}
167827bd09bSSatish Balay 
168827bd09bSSatish Balay 	  dest = my_id^mask;
169827bd09bSSatish Balay 	  if (my_id < dest)
1703fdc5746SBarry Smith 	    {ierr = MPI_Send(vals,n,MPIU_INT,dest,MSGTAG4+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
171827bd09bSSatish Balay 	  else
172827bd09bSSatish Balay 	    {
1733fdc5746SBarry Smith 	      ierr = MPI_Recv(vals,n,MPIU_INT,MPI_ANY_SOURCE,MSGTAG4+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
174827bd09bSSatish Balay 	    }
175827bd09bSSatish Balay 	}
176827bd09bSSatish Balay     }
177827bd09bSSatish Balay 
178827bd09bSSatish Balay   /* if not a hypercube must expand to partial dim */
179827bd09bSSatish Balay   if (edge_not_pow_2)
180827bd09bSSatish Balay     {
181827bd09bSSatish Balay       if (my_id >= floor_num_nodes)
182827bd09bSSatish Balay 	{
1833fdc5746SBarry Smith 	  ierr = MPI_Recv(vals,n,MPIU_INT,MPI_ANY_SOURCE,MSGTAG5+edge_not_pow_2,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
184827bd09bSSatish Balay 	}
185827bd09bSSatish Balay       else
1863fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_INT,edge_not_pow_2,MSGTAG5+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
187827bd09bSSatish Balay     }
1883fdc5746SBarry Smith         PetscFunctionReturn(0);
189827bd09bSSatish Balay }
190827bd09bSSatish Balay 
191827bd09bSSatish Balay /***********************************comm.c*************************************
192827bd09bSSatish Balay Function: grop()
193827bd09bSSatish Balay 
194827bd09bSSatish Balay Input :
195827bd09bSSatish Balay Output:
196827bd09bSSatish Balay Return:
197827bd09bSSatish Balay Description: fan-in/out version
198827bd09bSSatish Balay ***********************************comm.c*************************************/
199*0924e98cSBarry Smith PetscErrorCode grop(PetscScalar *vals, PetscScalar *work, PetscInt n, int *oprs)
200827bd09bSSatish Balay {
2013fdc5746SBarry Smith    PetscInt mask, edge;
2023fdc5746SBarry Smith   PetscInt type, dest;
203827bd09bSSatish Balay   vfp fp;
204827bd09bSSatish Balay   MPI_Status  status;
2053fdc5746SBarry Smith   PetscErrorCode ierr;
206827bd09bSSatish Balay 
2073fdc5746SBarry Smith    PetscFunctionBegin;
208827bd09bSSatish Balay   /* ok ... should have some data, work, and operator(s) */
209827bd09bSSatish Balay   if (!vals||!work||!oprs)
21077431f27SBarry Smith     {error_msg_fatal("grop() :: vals=%D, work=%D, oprs=%D",vals,work,oprs);}
211827bd09bSSatish Balay 
212827bd09bSSatish Balay   /* non-uniform should have at least two entries */
213827bd09bSSatish Balay   if ((oprs[0] == NON_UNIFORM)&&(n<2))
214827bd09bSSatish Balay     {error_msg_fatal("grop() :: non_uniform and n=0,1?");}
215827bd09bSSatish Balay 
216827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
217827bd09bSSatish Balay   if (!p_init)
218827bd09bSSatish Balay     {comm_init();}
219827bd09bSSatish Balay 
220827bd09bSSatish Balay   /* if there's nothing to do return */
221827bd09bSSatish Balay   if ((num_nodes<2)||(!n))
2223fdc5746SBarry Smith     {        PetscFunctionReturn(0);}
223827bd09bSSatish Balay 
224827bd09bSSatish Balay   /* a negative number of items to send ==> fatal */
225827bd09bSSatish Balay   if (n<0)
22677431f27SBarry Smith     {error_msg_fatal("gdop() :: n=%D<0?",n);}
227827bd09bSSatish Balay 
228827bd09bSSatish Balay   /* advance to list of n operations for custom */
229827bd09bSSatish Balay   if ((type=oprs[0])==NON_UNIFORM)
230827bd09bSSatish Balay     {oprs++;}
231827bd09bSSatish Balay 
232d890fc11SSatish Balay   if (!(fp = (vfp) rvec_fct_addr(type))) {
233827bd09bSSatish Balay     error_msg_warning("grop() :: hope you passed in a rbfp!\n");
234827bd09bSSatish Balay     fp = (vfp) oprs;
235827bd09bSSatish Balay   }
236827bd09bSSatish Balay 
237827bd09bSSatish Balay   /* all msgs will be of the same length */
238827bd09bSSatish Balay   /* if not a hypercube must colapse partial dim */
239827bd09bSSatish Balay   if (edge_not_pow_2)
240827bd09bSSatish Balay     {
241827bd09bSSatish Balay       if (my_id >= floor_num_nodes)
2423fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_SCALAR,edge_not_pow_2,MSGTAG0+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
243827bd09bSSatish Balay       else
244827bd09bSSatish Balay 	{
2453fdc5746SBarry Smith 	  ierr = MPI_Recv(work,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG0+edge_not_pow_2,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
246827bd09bSSatish Balay 	  (*fp)(vals,work,n,oprs);
247827bd09bSSatish Balay 	}
248827bd09bSSatish Balay     }
249827bd09bSSatish Balay 
250827bd09bSSatish Balay   /* implement the mesh fan in/out exchange algorithm */
251827bd09bSSatish Balay   if (my_id<floor_num_nodes)
252827bd09bSSatish Balay     {
253827bd09bSSatish Balay       for (mask=1,edge=0; edge<i_log2_num_nodes; edge++,mask<<=1)
254827bd09bSSatish Balay 	{
255827bd09bSSatish Balay 	  dest = my_id^mask;
256827bd09bSSatish Balay 	  if (my_id > dest)
2573fdc5746SBarry Smith 	    {ierr = MPI_Send(vals,n,MPIU_SCALAR,dest,MSGTAG2+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
258827bd09bSSatish Balay 	  else
259827bd09bSSatish Balay 	    {
2603fdc5746SBarry Smith 	      ierr = MPI_Recv(work,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG2+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
261827bd09bSSatish Balay 	      (*fp)(vals, work, n, oprs);
262827bd09bSSatish Balay 	    }
263827bd09bSSatish Balay 	}
264827bd09bSSatish Balay 
265827bd09bSSatish Balay       mask=floor_num_nodes>>1;
266827bd09bSSatish Balay       for (edge=0; edge<i_log2_num_nodes; edge++,mask>>=1)
267827bd09bSSatish Balay 	{
268827bd09bSSatish Balay 	  if (my_id%mask)
269827bd09bSSatish Balay 	    {continue;}
270827bd09bSSatish Balay 
271827bd09bSSatish Balay 	  dest = my_id^mask;
272827bd09bSSatish Balay 	  if (my_id < dest)
2733fdc5746SBarry Smith 	    {ierr = MPI_Send(vals,n,MPIU_SCALAR,dest,MSGTAG4+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
274827bd09bSSatish Balay 	  else
275827bd09bSSatish Balay 	    {
2763fdc5746SBarry Smith 	      ierr = MPI_Recv(vals,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG4+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
277827bd09bSSatish Balay 	    }
278827bd09bSSatish Balay 	}
279827bd09bSSatish Balay     }
280827bd09bSSatish Balay 
281827bd09bSSatish Balay   /* if not a hypercube must expand to partial dim */
282827bd09bSSatish Balay   if (edge_not_pow_2)
283827bd09bSSatish Balay     {
284827bd09bSSatish Balay       if (my_id >= floor_num_nodes)
285827bd09bSSatish Balay 	{
2863fdc5746SBarry Smith 	  ierr = MPI_Recv(vals,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG5+edge_not_pow_2, MPI_COMM_WORLD,&status);CHKERRQ(ierr);
287827bd09bSSatish Balay 	}
288827bd09bSSatish Balay       else
2893fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_SCALAR,edge_not_pow_2,MSGTAG5+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
290827bd09bSSatish Balay     }
2913fdc5746SBarry Smith         PetscFunctionReturn(0);
292827bd09bSSatish Balay }
293827bd09bSSatish Balay 
294827bd09bSSatish Balay 
295827bd09bSSatish Balay /***********************************comm.c*************************************
296827bd09bSSatish Balay Function: grop()
297827bd09bSSatish Balay 
298827bd09bSSatish Balay Input :
299827bd09bSSatish Balay Output:
300827bd09bSSatish Balay Return:
301827bd09bSSatish Balay Description: fan-in/out version
302827bd09bSSatish Balay 
303827bd09bSSatish Balay note good only for num_nodes=2^k!!!
304827bd09bSSatish Balay 
305827bd09bSSatish Balay ***********************************comm.c*************************************/
306*0924e98cSBarry Smith PetscErrorCode grop_hc(PetscScalar *vals, PetscScalar *work, PetscInt n, int *oprs, PetscInt dim)
307827bd09bSSatish Balay {
3083fdc5746SBarry Smith    PetscInt mask, edge;
3093fdc5746SBarry Smith   PetscInt type, dest;
310827bd09bSSatish Balay   vfp fp;
311827bd09bSSatish Balay   MPI_Status  status;
3123fdc5746SBarry Smith   PetscErrorCode ierr;
313827bd09bSSatish Balay 
3143fdc5746SBarry Smith    PetscFunctionBegin;
315827bd09bSSatish Balay   /* ok ... should have some data, work, and operator(s) */
316827bd09bSSatish Balay   if (!vals||!work||!oprs)
31777431f27SBarry Smith     {error_msg_fatal("grop_hc() :: vals=%D, work=%D, oprs=%D",vals,work,oprs);}
318827bd09bSSatish Balay 
319827bd09bSSatish Balay   /* non-uniform should have at least two entries */
320827bd09bSSatish Balay   if ((oprs[0] == NON_UNIFORM)&&(n<2))
321827bd09bSSatish Balay     {error_msg_fatal("grop_hc() :: non_uniform and n=0,1?");}
322827bd09bSSatish Balay 
323827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
324827bd09bSSatish Balay   if (!p_init)
325827bd09bSSatish Balay     {comm_init();}
326827bd09bSSatish Balay 
327827bd09bSSatish Balay   /* if there's nothing to do return */
328827bd09bSSatish Balay   if ((num_nodes<2)||(!n)||(dim<=0))
329*0924e98cSBarry Smith     {PetscFunctionReturn(0);}
330827bd09bSSatish Balay 
331827bd09bSSatish Balay   /* the error msg says it all!!! */
332827bd09bSSatish Balay   if (modfl_num_nodes)
333827bd09bSSatish Balay     {error_msg_fatal("grop_hc() :: num_nodes not a power of 2!?!");}
334827bd09bSSatish Balay 
335827bd09bSSatish Balay   /* a negative number of items to send ==> fatal */
336827bd09bSSatish Balay   if (n<0)
33777431f27SBarry Smith     {error_msg_fatal("grop_hc() :: n=%D<0?",n);}
338827bd09bSSatish Balay 
339827bd09bSSatish Balay   /* can't do more dimensions then exist */
34039945688SSatish Balay   dim = PetscMin(dim,i_log2_num_nodes);
341827bd09bSSatish Balay 
342827bd09bSSatish Balay   /* advance to list of n operations for custom */
343827bd09bSSatish Balay   if ((type=oprs[0])==NON_UNIFORM)
344827bd09bSSatish Balay     {oprs++;}
345827bd09bSSatish Balay 
346d890fc11SSatish Balay   if (!(fp = (vfp) rvec_fct_addr(type))) {
347827bd09bSSatish Balay     error_msg_warning("grop_hc() :: hope you passed in a rbfp!\n");
348827bd09bSSatish Balay     fp = (vfp) oprs;
349827bd09bSSatish Balay   }
350827bd09bSSatish Balay 
351827bd09bSSatish Balay   for (mask=1,edge=0; edge<dim; edge++,mask<<=1)
352827bd09bSSatish Balay     {
353827bd09bSSatish Balay       dest = my_id^mask;
354827bd09bSSatish Balay       if (my_id > dest)
3553fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_SCALAR,dest,MSGTAG2+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
356827bd09bSSatish Balay       else
357827bd09bSSatish Balay 	{
3583fdc5746SBarry Smith 	  ierr = MPI_Recv(work,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG2+dest,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
359827bd09bSSatish Balay 	  (*fp)(vals, work, n, oprs);
360827bd09bSSatish Balay 	}
361827bd09bSSatish Balay     }
362827bd09bSSatish Balay 
363827bd09bSSatish Balay   if (edge==dim)
364827bd09bSSatish Balay     {mask>>=1;}
365827bd09bSSatish Balay   else
366827bd09bSSatish Balay     {while (++edge<dim) {mask<<=1;}}
367827bd09bSSatish Balay 
368827bd09bSSatish Balay   for (edge=0; edge<dim; edge++,mask>>=1)
369827bd09bSSatish Balay     {
370827bd09bSSatish Balay       if (my_id%mask)
371827bd09bSSatish Balay 	{continue;}
372827bd09bSSatish Balay 
373827bd09bSSatish Balay       dest = my_id^mask;
374827bd09bSSatish Balay       if (my_id < dest)
3753fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_SCALAR,dest,MSGTAG4+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
376827bd09bSSatish Balay       else
377827bd09bSSatish Balay 	{
3783fdc5746SBarry Smith 	  ierr = MPI_Recv(vals,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG4+dest,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
379827bd09bSSatish Balay 	}
380827bd09bSSatish Balay     }
3813fdc5746SBarry Smith         PetscFunctionReturn(0);
382827bd09bSSatish Balay }
383827bd09bSSatish Balay 
384827bd09bSSatish Balay 
385827bd09bSSatish Balay /***********************************comm.c*************************************
386827bd09bSSatish Balay Function: gop()
387827bd09bSSatish Balay 
388827bd09bSSatish Balay Input :
389827bd09bSSatish Balay Output:
390827bd09bSSatish Balay Return:
391827bd09bSSatish Balay Description: fan-in/out version
392827bd09bSSatish Balay ***********************************comm.c*************************************/
3933fdc5746SBarry Smith PetscErrorCode gfop(void *vals, void *work, PetscInt n, vbfp fp, MPI_Datatype dt, int comm_type)
394827bd09bSSatish Balay {
3953fdc5746SBarry Smith    PetscInt mask, edge;
3963fdc5746SBarry Smith   PetscInt dest;
397827bd09bSSatish Balay   MPI_Status  status;
398827bd09bSSatish Balay   MPI_Op op;
3993fdc5746SBarry Smith   PetscErrorCode ierr;
400827bd09bSSatish Balay 
4013fdc5746SBarry Smith    PetscFunctionBegin;
402827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
403827bd09bSSatish Balay   if (!p_init)
404827bd09bSSatish Balay     {comm_init();}
405827bd09bSSatish Balay 
406827bd09bSSatish Balay   /* ok ... should have some data, work, and operator(s) */
407827bd09bSSatish Balay   if (!vals||!work||!fp)
40877431f27SBarry Smith     {error_msg_fatal("gop() :: v=%D, w=%D, f=%D",vals,work,fp);}
409827bd09bSSatish Balay 
410827bd09bSSatish Balay   /* if there's nothing to do return */
411827bd09bSSatish Balay   if ((num_nodes<2)||(!n))
4123fdc5746SBarry Smith     {CHKERRQ(ierr);}
413827bd09bSSatish Balay 
414827bd09bSSatish Balay   /* a negative number of items to send ==> fatal */
415827bd09bSSatish Balay   if (n<0)
41677431f27SBarry Smith     {error_msg_fatal("gop() :: n=%D<0?",n);}
417827bd09bSSatish Balay 
418827bd09bSSatish Balay   if (comm_type==MPI)
419827bd09bSSatish Balay     {
4203fdc5746SBarry Smith       ierr = MPI_Op_create(fp,TRUE,&op);CHKERRQ(ierr);
4213fdc5746SBarry Smith       ierr = MPI_Allreduce (vals, work, n, dt, op, MPI_COMM_WORLD);CHKERRQ(ierr);
4223fdc5746SBarry Smith       ierr = MPI_Op_free(&op);CHKERRQ(ierr);
4233fdc5746SBarry Smith       CHKERRQ(ierr);
424827bd09bSSatish Balay     }
425827bd09bSSatish Balay 
426827bd09bSSatish Balay   /* if not a hypercube must colapse partial dim */
427827bd09bSSatish Balay   if (edge_not_pow_2)
428827bd09bSSatish Balay     {
429827bd09bSSatish Balay       if (my_id >= floor_num_nodes)
4303fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,dt,edge_not_pow_2,MSGTAG0+my_id, MPI_COMM_WORLD);CHKERRQ(ierr);}
431827bd09bSSatish Balay       else
432827bd09bSSatish Balay 	{
4333fdc5746SBarry Smith 	  ierr = MPI_Recv(work,n,dt,MPI_ANY_SOURCE,MSGTAG0+edge_not_pow_2,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
434827bd09bSSatish Balay 	  (*fp)(vals,work,&n,&dt);
435827bd09bSSatish Balay 	}
436827bd09bSSatish Balay     }
437827bd09bSSatish Balay 
438827bd09bSSatish Balay   /* implement the mesh fan in/out exchange algorithm */
439827bd09bSSatish Balay   if (my_id<floor_num_nodes)
440827bd09bSSatish Balay     {
441827bd09bSSatish Balay       for (mask=1,edge=0; edge<i_log2_num_nodes; edge++,mask<<=1)
442827bd09bSSatish Balay 	{
443827bd09bSSatish Balay 	  dest = my_id^mask;
444827bd09bSSatish Balay 	  if (my_id > dest)
4453fdc5746SBarry Smith 	    {ierr = MPI_Send(vals,n,dt,dest,MSGTAG2+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
446827bd09bSSatish Balay 	  else
447827bd09bSSatish Balay 	    {
4483fdc5746SBarry Smith 	      ierr = MPI_Recv(work,n,dt,MPI_ANY_SOURCE,MSGTAG2+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
449827bd09bSSatish Balay 	      (*fp)(vals, work, &n, &dt);
450827bd09bSSatish Balay 	    }
451827bd09bSSatish Balay 	}
452827bd09bSSatish Balay 
453827bd09bSSatish Balay       mask=floor_num_nodes>>1;
454827bd09bSSatish Balay       for (edge=0; edge<i_log2_num_nodes; edge++,mask>>=1)
455827bd09bSSatish Balay 	{
456827bd09bSSatish Balay 	  if (my_id%mask)
457827bd09bSSatish Balay 	    {continue;}
458827bd09bSSatish Balay 
459827bd09bSSatish Balay 	  dest = my_id^mask;
460827bd09bSSatish Balay 	  if (my_id < dest)
4613fdc5746SBarry Smith 	    {ierr = MPI_Send(vals,n,dt,dest,MSGTAG4+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
462827bd09bSSatish Balay 	  else
463827bd09bSSatish Balay 	    {
4643fdc5746SBarry Smith 	      ierr = MPI_Recv(vals,n,dt,MPI_ANY_SOURCE,MSGTAG4+dest, MPI_COMM_WORLD, &status);CHKERRQ(ierr);
465827bd09bSSatish Balay 	    }
466827bd09bSSatish Balay 	}
467827bd09bSSatish Balay     }
468827bd09bSSatish Balay 
469827bd09bSSatish Balay   /* if not a hypercube must expand to partial dim */
470827bd09bSSatish Balay   if (edge_not_pow_2)
471827bd09bSSatish Balay     {
472827bd09bSSatish Balay       if (my_id >= floor_num_nodes)
473827bd09bSSatish Balay 	{
4743fdc5746SBarry Smith 	  ierr = MPI_Recv(vals,n,dt,MPI_ANY_SOURCE,MSGTAG5+edge_not_pow_2, MPI_COMM_WORLD,&status);CHKERRQ(ierr);
475827bd09bSSatish Balay 	}
476827bd09bSSatish Balay       else
4773fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,dt,edge_not_pow_2,MSGTAG5+my_id, MPI_COMM_WORLD);CHKERRQ(ierr);}
478827bd09bSSatish Balay     }
4793fdc5746SBarry Smith   PetscFunctionReturn(0);
480827bd09bSSatish Balay }
481827bd09bSSatish Balay 
482827bd09bSSatish Balay 
483827bd09bSSatish Balay 
484827bd09bSSatish Balay 
485827bd09bSSatish Balay 
486827bd09bSSatish Balay 
487827bd09bSSatish Balay /******************************************************************************
488827bd09bSSatish Balay Function: giop()
489827bd09bSSatish Balay 
490827bd09bSSatish Balay Input :
491827bd09bSSatish Balay Output:
492827bd09bSSatish Balay Return:
493827bd09bSSatish Balay Description:
494827bd09bSSatish Balay 
495827bd09bSSatish Balay ii+1 entries in seg :: 0 .. ii
496827bd09bSSatish Balay 
497827bd09bSSatish Balay ******************************************************************************/
498*0924e98cSBarry Smith PetscErrorCode ssgl_radd( PetscScalar *vals,  PetscScalar *work,  PetscInt level, PetscInt *segs)
499827bd09bSSatish Balay {
5003fdc5746SBarry Smith    PetscInt edge, type, dest, mask;
5013fdc5746SBarry Smith    PetscInt stage_n;
502827bd09bSSatish Balay   MPI_Status  status;
5033fdc5746SBarry Smith   PetscErrorCode ierr;
504827bd09bSSatish Balay 
5053fdc5746SBarry Smith    PetscFunctionBegin;
506827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
507827bd09bSSatish Balay   if (!p_init)
508827bd09bSSatish Balay     {comm_init();}
509827bd09bSSatish Balay 
510827bd09bSSatish Balay 
511827bd09bSSatish Balay   /* all msgs are *NOT* the same length */
512827bd09bSSatish Balay   /* implement the mesh fan in/out exchange algorithm */
513827bd09bSSatish Balay   for (mask=0, edge=0; edge<level; edge++, mask++)
514827bd09bSSatish Balay     {
515827bd09bSSatish Balay       stage_n = (segs[level] - segs[edge]);
516827bd09bSSatish Balay       if (stage_n && !(my_id & mask))
517827bd09bSSatish Balay 	{
518827bd09bSSatish Balay 	  dest = edge_node[edge];
519827bd09bSSatish Balay 	  type = MSGTAG3 + my_id + (num_nodes*edge);
520827bd09bSSatish Balay 	  if (my_id>dest)
5213fdc5746SBarry Smith           {ierr = MPI_Send(vals+segs[edge],stage_n,MPIU_SCALAR,dest,type, MPI_COMM_WORLD);CHKERRQ(ierr);}
522827bd09bSSatish Balay 	  else
523827bd09bSSatish Balay 	    {
524827bd09bSSatish Balay 	      type =  type - my_id + dest;
5253fdc5746SBarry Smith               ierr = MPI_Recv(work,stage_n,MPIU_SCALAR,MPI_ANY_SOURCE,type,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
526827bd09bSSatish Balay 	      rvec_add(vals+segs[edge], work, stage_n);
527827bd09bSSatish Balay 	    }
528827bd09bSSatish Balay 	}
529827bd09bSSatish Balay       mask <<= 1;
530827bd09bSSatish Balay     }
531827bd09bSSatish Balay   mask>>=1;
532827bd09bSSatish Balay   for (edge=0; edge<level; edge++)
533827bd09bSSatish Balay     {
534827bd09bSSatish Balay       stage_n = (segs[level] - segs[level-1-edge]);
535827bd09bSSatish Balay       if (stage_n && !(my_id & mask))
536827bd09bSSatish Balay 	{
537827bd09bSSatish Balay 	  dest = edge_node[level-edge-1];
538827bd09bSSatish Balay 	  type = MSGTAG6 + my_id + (num_nodes*edge);
539827bd09bSSatish Balay 	  if (my_id<dest)
5403fdc5746SBarry Smith             {ierr = MPI_Send(vals+segs[level-1-edge],stage_n,MPIU_SCALAR,dest,type,MPI_COMM_WORLD);CHKERRQ(ierr);}
541827bd09bSSatish Balay 	  else
542827bd09bSSatish Balay 	    {
543827bd09bSSatish Balay 	      type =  type - my_id + dest;
5443fdc5746SBarry Smith               ierr = MPI_Recv(vals+segs[level-1-edge],stage_n,MPIU_SCALAR, MPI_ANY_SOURCE,type,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
545827bd09bSSatish Balay 	    }
546827bd09bSSatish Balay 	}
547827bd09bSSatish Balay       mask >>= 1;
548827bd09bSSatish Balay     }
5493fdc5746SBarry Smith   PetscFunctionReturn(0);
550827bd09bSSatish Balay }
551827bd09bSSatish Balay 
552827bd09bSSatish Balay 
553827bd09bSSatish Balay 
554827bd09bSSatish Balay /***********************************comm.c*************************************
555827bd09bSSatish Balay Function: grop_hc_vvl()
556827bd09bSSatish Balay 
557827bd09bSSatish Balay Input :
558827bd09bSSatish Balay Output:
559827bd09bSSatish Balay Return:
560827bd09bSSatish Balay Description: fan-in/out version
561827bd09bSSatish Balay 
562827bd09bSSatish Balay note good only for num_nodes=2^k!!!
563827bd09bSSatish Balay 
564827bd09bSSatish Balay ***********************************comm.c*************************************/
565*0924e98cSBarry Smith PetscErrorCode grop_hc_vvl(PetscScalar *vals, PetscScalar *work, PetscInt *segs, PetscInt *oprs, PetscInt dim)
566827bd09bSSatish Balay {
5673fdc5746SBarry Smith    PetscInt mask, edge, n;
5683fdc5746SBarry Smith   PetscInt type, dest;
569827bd09bSSatish Balay   vfp fp;
570827bd09bSSatish Balay   MPI_Status  status;
5713fdc5746SBarry Smith   PetscErrorCode ierr;
572827bd09bSSatish Balay 
5733fdc5746SBarry Smith    PetscFunctionBegin;
574827bd09bSSatish Balay   error_msg_fatal("grop_hc_vvl() :: is not working!\n");
575827bd09bSSatish Balay 
576827bd09bSSatish Balay   /* ok ... should have some data, work, and operator(s) */
577827bd09bSSatish Balay   if (!vals||!work||!oprs||!segs)
57877431f27SBarry Smith     {error_msg_fatal("grop_hc() :: vals=%D, work=%D, oprs=%D",vals,work,oprs);}
579827bd09bSSatish Balay 
580827bd09bSSatish Balay   /* non-uniform should have at least two entries */
581827bd09bSSatish Balay 
582827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
583827bd09bSSatish Balay   if (!p_init)
584827bd09bSSatish Balay     {comm_init();}
585827bd09bSSatish Balay 
586827bd09bSSatish Balay   /* if there's nothing to do return */
587827bd09bSSatish Balay   if ((num_nodes<2)||(dim<=0))
5883fdc5746SBarry Smith     {PetscFunctionReturn(0);}
589827bd09bSSatish Balay 
590827bd09bSSatish Balay   /* the error msg says it all!!! */
591827bd09bSSatish Balay   if (modfl_num_nodes)
592827bd09bSSatish Balay     {error_msg_fatal("grop_hc() :: num_nodes not a power of 2!?!");}
593827bd09bSSatish Balay 
594827bd09bSSatish Balay   /* can't do more dimensions then exist */
59539945688SSatish Balay   dim = PetscMin(dim,i_log2_num_nodes);
596827bd09bSSatish Balay 
597827bd09bSSatish Balay   /* advance to list of n operations for custom */
598827bd09bSSatish Balay   if ((type=oprs[0])==NON_UNIFORM)
599827bd09bSSatish Balay     {oprs++;}
600827bd09bSSatish Balay 
601d890fc11SSatish Balay   if (!(fp = (vfp) rvec_fct_addr(type))){
602827bd09bSSatish Balay     error_msg_warning("grop_hc() :: hope you passed in a rbfp!\n");
603827bd09bSSatish Balay     fp = (vfp) oprs;
604827bd09bSSatish Balay   }
605827bd09bSSatish Balay 
606827bd09bSSatish Balay   for (mask=1,edge=0; edge<dim; edge++,mask<<=1)
607827bd09bSSatish Balay     {
608827bd09bSSatish Balay       n = segs[dim]-segs[edge];
609827bd09bSSatish Balay       dest = my_id^mask;
610827bd09bSSatish Balay       if (my_id > dest)
6113fdc5746SBarry Smith 	{ierr = MPI_Send(vals+segs[edge],n,MPIU_SCALAR,dest,MSGTAG2+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
612827bd09bSSatish Balay       else
613827bd09bSSatish Balay 	{
6143fdc5746SBarry Smith 	  ierr = MPI_Recv(work,n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG2+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
615827bd09bSSatish Balay 	  (*fp)(vals+segs[edge], work, n, oprs);
616827bd09bSSatish Balay 	}
617827bd09bSSatish Balay     }
618827bd09bSSatish Balay 
619827bd09bSSatish Balay   if (edge==dim)
620827bd09bSSatish Balay     {mask>>=1;}
621827bd09bSSatish Balay   else
622827bd09bSSatish Balay     {while (++edge<dim) {mask<<=1;}}
623827bd09bSSatish Balay 
624827bd09bSSatish Balay   for (edge=0; edge<dim; edge++,mask>>=1)
625827bd09bSSatish Balay     {
626827bd09bSSatish Balay       if (my_id%mask)
627827bd09bSSatish Balay 	{continue;}
628827bd09bSSatish Balay 
629827bd09bSSatish Balay       n = (segs[dim]-segs[dim-1-edge]);
630827bd09bSSatish Balay 
631827bd09bSSatish Balay       dest = my_id^mask;
632827bd09bSSatish Balay       if (my_id < dest)
6333fdc5746SBarry Smith 	{ierr = MPI_Send(vals+segs[dim-1-edge],n,MPIU_SCALAR,dest,MSGTAG4+my_id, MPI_COMM_WORLD);CHKERRQ(ierr);}
634827bd09bSSatish Balay       else
635827bd09bSSatish Balay 	{
6363fdc5746SBarry Smith 	  ierr = MPI_Recv(vals+segs[dim-1-edge],n,MPIU_SCALAR,MPI_ANY_SOURCE,MSGTAG4+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
637827bd09bSSatish Balay 	}
638827bd09bSSatish Balay     }
6393fdc5746SBarry Smith   PetscFunctionReturn(0);
640827bd09bSSatish Balay }
641827bd09bSSatish Balay 
642827bd09bSSatish Balay /******************************************************************************
643827bd09bSSatish Balay Function: giop()
644827bd09bSSatish Balay 
645827bd09bSSatish Balay Input :
646827bd09bSSatish Balay Output:
647827bd09bSSatish Balay Return:
648827bd09bSSatish Balay Description:
649827bd09bSSatish Balay 
650827bd09bSSatish Balay ii+1 entries in seg :: 0 .. ii
651827bd09bSSatish Balay 
652827bd09bSSatish Balay ******************************************************************************/
6533fdc5746SBarry Smith PetscErrorCode new_ssgl_radd( PetscScalar *vals,  PetscScalar *work,  int level, int *segs)
654827bd09bSSatish Balay {
655a501084fSBarry Smith    int edge, type, dest, mask;
656a501084fSBarry Smith    int stage_n;
657827bd09bSSatish Balay   MPI_Status  status;
6583fdc5746SBarry Smith   PetscErrorCode ierr;
659827bd09bSSatish Balay 
6603fdc5746SBarry Smith    PetscFunctionBegin;
661827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
662827bd09bSSatish Balay   if (!p_init)
663827bd09bSSatish Balay     {comm_init();}
664827bd09bSSatish Balay 
665827bd09bSSatish Balay   /* all msgs are *NOT* the same length */
666827bd09bSSatish Balay   /* implement the mesh fan in/out exchange algorithm */
667827bd09bSSatish Balay   for (mask=0, edge=0; edge<level; edge++, mask++)
668827bd09bSSatish Balay     {
669827bd09bSSatish Balay       stage_n = (segs[level] - segs[edge]);
670827bd09bSSatish Balay       if (stage_n && !(my_id & mask))
671827bd09bSSatish Balay 	{
672827bd09bSSatish Balay 	  dest = edge_node[edge];
673827bd09bSSatish Balay 	  type = MSGTAG3 + my_id + (num_nodes*edge);
674827bd09bSSatish Balay 	  if (my_id>dest)
6753fdc5746SBarry Smith           {ierr = MPI_Send(vals+segs[edge],stage_n,MPIU_SCALAR,dest,type, MPI_COMM_WORLD);CHKERRQ(ierr);}
676827bd09bSSatish Balay 	  else
677827bd09bSSatish Balay 	    {
678827bd09bSSatish Balay 	      type =  type - my_id + dest;
6793fdc5746SBarry Smith               ierr = MPI_Recv(work,stage_n,MPIU_SCALAR,MPI_ANY_SOURCE,type, MPI_COMM_WORLD,&status);CHKERRQ(ierr);
680827bd09bSSatish Balay 	      rvec_add(vals+segs[edge], work, stage_n);
681827bd09bSSatish Balay 	    }
682827bd09bSSatish Balay 	}
683827bd09bSSatish Balay       mask <<= 1;
684827bd09bSSatish Balay     }
685827bd09bSSatish Balay   mask>>=1;
686827bd09bSSatish Balay   for (edge=0; edge<level; edge++)
687827bd09bSSatish Balay     {
688827bd09bSSatish Balay       stage_n = (segs[level] - segs[level-1-edge]);
689827bd09bSSatish Balay       if (stage_n && !(my_id & mask))
690827bd09bSSatish Balay 	{
691827bd09bSSatish Balay 	  dest = edge_node[level-edge-1];
692827bd09bSSatish Balay 	  type = MSGTAG6 + my_id + (num_nodes*edge);
693827bd09bSSatish Balay 	  if (my_id<dest)
6943fdc5746SBarry Smith             {ierr = MPI_Send(vals+segs[level-1-edge],stage_n,MPIU_SCALAR,dest,type,MPI_COMM_WORLD);CHKERRQ(ierr);}
695827bd09bSSatish Balay 	  else
696827bd09bSSatish Balay 	    {
697827bd09bSSatish Balay 	      type =  type - my_id + dest;
6983fdc5746SBarry Smith               ierr = MPI_Recv(vals+segs[level-1-edge],stage_n,MPIU_SCALAR, MPI_ANY_SOURCE,type,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
699827bd09bSSatish Balay 	    }
700827bd09bSSatish Balay 	}
701827bd09bSSatish Balay       mask >>= 1;
702827bd09bSSatish Balay     }
7033fdc5746SBarry Smith   PetscFunctionReturn(0);
704827bd09bSSatish Balay }
705827bd09bSSatish Balay 
706827bd09bSSatish Balay 
707827bd09bSSatish Balay 
708827bd09bSSatish Balay /***********************************comm.c*************************************
709827bd09bSSatish Balay Function: giop()
710827bd09bSSatish Balay 
711827bd09bSSatish Balay Input :
712827bd09bSSatish Balay Output:
713827bd09bSSatish Balay Return:
714827bd09bSSatish Balay Description: fan-in/out version
715827bd09bSSatish Balay 
716827bd09bSSatish Balay note good only for num_nodes=2^k!!!
717827bd09bSSatish Balay 
718827bd09bSSatish Balay ***********************************comm.c*************************************/
7193fdc5746SBarry Smith PetscErrorCode giop_hc(int *vals, int *work, int n, int *oprs, int dim)
720827bd09bSSatish Balay {
721a501084fSBarry Smith    int mask, edge;
722827bd09bSSatish Balay   int type, dest;
723827bd09bSSatish Balay   vfp fp;
724827bd09bSSatish Balay   MPI_Status  status;
7253fdc5746SBarry Smith   PetscErrorCode ierr;
726827bd09bSSatish Balay 
7273fdc5746SBarry Smith    PetscFunctionBegin;
728827bd09bSSatish Balay   /* ok ... should have some data, work, and operator(s) */
729827bd09bSSatish Balay   if (!vals||!work||!oprs)
73077431f27SBarry Smith     {error_msg_fatal("giop_hc() :: vals=%D, work=%D, oprs=%D",vals,work,oprs);}
731827bd09bSSatish Balay 
732827bd09bSSatish Balay   /* non-uniform should have at least two entries */
733827bd09bSSatish Balay   if ((oprs[0] == NON_UNIFORM)&&(n<2))
734827bd09bSSatish Balay     {error_msg_fatal("giop_hc() :: non_uniform and n=0,1?");}
735827bd09bSSatish Balay 
736827bd09bSSatish Balay   /* check to make sure comm package has been initialized */
737827bd09bSSatish Balay   if (!p_init)
738827bd09bSSatish Balay     {comm_init();}
739827bd09bSSatish Balay 
740827bd09bSSatish Balay   /* if there's nothing to do return */
741827bd09bSSatish Balay   if ((num_nodes<2)||(!n)||(dim<=0))
7423fdc5746SBarry Smith     {  PetscFunctionReturn(0);}
743827bd09bSSatish Balay 
744827bd09bSSatish Balay   /* the error msg says it all!!! */
745827bd09bSSatish Balay   if (modfl_num_nodes)
746827bd09bSSatish Balay     {error_msg_fatal("giop_hc() :: num_nodes not a power of 2!?!");}
747827bd09bSSatish Balay 
748827bd09bSSatish Balay   /* a negative number of items to send ==> fatal */
749827bd09bSSatish Balay   if (n<0)
75077431f27SBarry Smith     {error_msg_fatal("giop_hc() :: n=%D<0?",n);}
751827bd09bSSatish Balay 
752827bd09bSSatish Balay   /* can't do more dimensions then exist */
75339945688SSatish Balay   dim = PetscMin(dim,i_log2_num_nodes);
754827bd09bSSatish Balay 
755827bd09bSSatish Balay   /* advance to list of n operations for custom */
756827bd09bSSatish Balay   if ((type=oprs[0])==NON_UNIFORM)
757827bd09bSSatish Balay     {oprs++;}
758827bd09bSSatish Balay 
759d890fc11SSatish Balay   if (!(fp = (vfp) ivec_fct_addr(type))){
760827bd09bSSatish Balay     error_msg_warning("giop_hc() :: hope you passed in a rbfp!\n");
761827bd09bSSatish Balay     fp = (vfp) oprs;
762827bd09bSSatish Balay   }
763827bd09bSSatish Balay 
764827bd09bSSatish Balay   for (mask=1,edge=0; edge<dim; edge++,mask<<=1)
765827bd09bSSatish Balay     {
766827bd09bSSatish Balay       dest = my_id^mask;
767827bd09bSSatish Balay       if (my_id > dest)
7683fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_INT,dest,MSGTAG2+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
769827bd09bSSatish Balay       else
770827bd09bSSatish Balay 	{
7713fdc5746SBarry Smith 	  ierr = MPI_Recv(work,n,MPIU_INT,MPI_ANY_SOURCE,MSGTAG2+dest,MPI_COMM_WORLD, &status);CHKERRQ(ierr);
772827bd09bSSatish Balay 	  (*fp)(vals, work, n, oprs);
773827bd09bSSatish Balay 	}
774827bd09bSSatish Balay     }
775827bd09bSSatish Balay 
776827bd09bSSatish Balay   if (edge==dim)
777827bd09bSSatish Balay     {mask>>=1;}
778827bd09bSSatish Balay   else
779827bd09bSSatish Balay     {while (++edge<dim) {mask<<=1;}}
780827bd09bSSatish Balay 
781827bd09bSSatish Balay   for (edge=0; edge<dim; edge++,mask>>=1)
782827bd09bSSatish Balay     {
783827bd09bSSatish Balay       if (my_id%mask)
784827bd09bSSatish Balay 	{continue;}
785827bd09bSSatish Balay 
786827bd09bSSatish Balay       dest = my_id^mask;
787827bd09bSSatish Balay       if (my_id < dest)
7883fdc5746SBarry Smith 	{ierr = MPI_Send(vals,n,MPIU_INT,dest,MSGTAG4+my_id,MPI_COMM_WORLD);CHKERRQ(ierr);}
789827bd09bSSatish Balay       else
790827bd09bSSatish Balay 	{
7913fdc5746SBarry Smith 	  ierr = MPI_Recv(vals,n,MPIU_INT,MPI_ANY_SOURCE,MSGTAG4+dest,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
792827bd09bSSatish Balay 	}
793827bd09bSSatish Balay     }
7943fdc5746SBarry Smith   PetscFunctionReturn(0);
795827bd09bSSatish Balay }
796