xref: /petsc/src/vec/is/utils/isltog.c (revision c8a8475e04bcaa43590892a5c3e60c6f87bc31f7)
1 /*$Id: isltog.c,v 1.65 2001/05/21 14:16:29 bsmith Exp $*/
2 
3 #include "petscsys.h"   /*I "petscsys.h" I*/
4 #include "src/vec/is/isimpl.h"    /*I "petscis.h"  I*/
5 
6 EXTERN int VecInitializePackage(char *);
7 
8 #undef __FUNCT__
9 #define __FUNCT__ "ISLocalToGlobalMappingGetSize"
10 /*@C
11     ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping.
12 
13     Not Collective
14 
15     Input Parameter:
16 .   ltog - local to global mapping
17 
18     Output Parameter:
19 .   n - the number of entries in the local mapping
20 
21     Level: advanced
22 
23     Concepts: mapping^local to global
24 
25 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate()
26 @*/
27 int ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping,int *n)
28 {
29   PetscFunctionBegin;
30   PetscValidHeaderSpecific(mapping,IS_LTOGM_COOKIE);
31   *n = mapping->n;
32   PetscFunctionReturn(0);
33 }
34 
35 #undef __FUNCT__
36 #define __FUNCT__ "ISLocalToGlobalMappingView"
37 /*@C
38     ISLocalToGlobalMappingView - View a local to global mapping
39 
40     Not Collective
41 
42     Input Parameters:
43 +   ltog - local to global mapping
44 -   viewer - viewer
45 
46     Level: advanced
47 
48     Concepts: mapping^local to global
49 
50 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate()
51 @*/
52 int ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping,PetscViewer viewer)
53 {
54   int        i,ierr,rank;
55   PetscTruth isascii;
56 
57   PetscFunctionBegin;
58   PetscValidHeaderSpecific(mapping,IS_LTOGM_COOKIE);
59   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(mapping->comm);
60   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_COOKIE);
61 
62   ierr = MPI_Comm_rank(mapping->comm,&rank);CHKERRQ(ierr);
63   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
64   if (isascii) {
65     for (i=0; i<mapping->n; i++) {
66       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %d %d\n",rank,i,mapping->indices[i]);CHKERRQ(ierr);
67     }
68     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
69   } else {
70     SETERRQ1(1,"Viewer type %s not supported for ISLocalToGlobalMapping",((PetscObject)viewer)->type_name);
71   }
72 
73   PetscFunctionReturn(0);
74 }
75 
76 #undef __FUNCT__
77 #define __FUNCT__ "ISLocalToGlobalMappingCreateIS"
78 /*@C
79     ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n)
80     ordering and a global parallel ordering.
81 
82     Not collective
83 
84     Input Parameter:
85 .   is - index set containing the global numbers for each local
86 
87     Output Parameter:
88 .   mapping - new mapping data structure
89 
90     Level: advanced
91 
92     Concepts: mapping^local to global
93 
94 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate()
95 @*/
96 int ISLocalToGlobalMappingCreateIS(IS is,ISLocalToGlobalMapping *mapping)
97 {
98   int      n,*indices,ierr;
99   MPI_Comm comm;
100 
101   PetscFunctionBegin;
102   PetscValidHeaderSpecific(is,IS_COOKIE);
103 
104   ierr = PetscObjectGetComm((PetscObject)is,&comm);CHKERRQ(ierr);
105   ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
106   ierr = ISGetIndices(is,&indices);CHKERRQ(ierr);
107   ierr = ISLocalToGlobalMappingCreate(comm,n,indices,mapping);CHKERRQ(ierr);
108   ierr = ISRestoreIndices(is,&indices);CHKERRQ(ierr);
109 
110   PetscFunctionReturn(0);
111 }
112 
113 
114 #undef __FUNCT__
115 #define __FUNCT__ "ISLocalToGlobalMappingCreate"
116 /*@C
117     ISLocalToGlobalMappingCreate - Creates a mapping between a local (0 to n)
118     ordering and a global parallel ordering.
119 
120     Not Collective, but communicator may have more than one process
121 
122     Input Parameters:
123 +   comm - MPI communicator
124 .   n - the number of local elements
125 -   indices - the global index for each local element
126 
127     Output Parameter:
128 .   mapping - new mapping data structure
129 
130     Level: advanced
131 
132     Concepts: mapping^local to global
133 
134 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreateNC()
135 @*/
136 int ISLocalToGlobalMappingCreate(MPI_Comm cm,int n,const int indices[],ISLocalToGlobalMapping *mapping)
137 {
138   int *in,ierr;
139 
140   PetscFunctionBegin;
141   PetscValidIntPointer(indices);
142   PetscValidPointer(mapping);
143   ierr = PetscMalloc((n+1)*sizeof(int),&in);CHKERRQ(ierr);
144   ierr = PetscMemcpy(in,indices,n*sizeof(int));CHKERRQ(ierr);
145   ierr = ISLocalToGlobalMappingCreateNC(cm,n,in,mapping);CHKERRQ(ierr);
146   PetscFunctionReturn(0);
147 }
148 
149 #undef __FUNCT__
150 #define __FUNCT__ "ISLocalToGlobalMappingCreateNC"
151 /*@C
152     ISLocalToGlobalMappingCreateNC - Creates a mapping between a local (0 to n)
153     ordering and a global parallel ordering.
154 
155     Not Collective, but communicator may have more than one process
156 
157     Input Parameters:
158 +   comm - MPI communicator
159 .   n - the number of local elements
160 -   indices - the global index for each local element
161 
162     Output Parameter:
163 .   mapping - new mapping data structure
164 
165     Level: developer
166 
167     Notes: Does not copy the indices, just keeps the pointer to the indices. The ISLocalToGlobalMappingDestroy()
168     will free the space so it must be obtained with PetscMalloc() and it must not be freed elsewhere.
169 
170     Concepts: mapping^local to global
171 
172 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate()
173 @*/
174 int ISLocalToGlobalMappingCreateNC(MPI_Comm cm,int n,const int indices[],ISLocalToGlobalMapping *mapping)
175 {
176   PetscFunctionBegin;
177   PetscValidIntPointer(indices);
178   PetscValidPointer(mapping);
179   *mapping = PETSC_NULL;
180 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
181   {int ierr = VecInitializePackage(PETSC_NULL);                                                                CHKERRQ(ierr);}
182 #endif
183 
184   PetscHeaderCreate(*mapping,_p_ISLocalToGlobalMapping,int,IS_LTOGM_COOKIE,0,"ISLocalToGlobalMapping",
185                     cm,ISLocalToGlobalMappingDestroy,ISLocalToGlobalMappingView);
186   PetscLogObjectCreate(*mapping);
187   PetscLogObjectMemory(*mapping,sizeof(struct _p_ISLocalToGlobalMapping)+n*sizeof(int));
188 
189   (*mapping)->n       = n;
190   (*mapping)->indices = (int*)indices;
191 
192   /*
193       Do not create the global to local mapping. This is only created if
194      ISGlobalToLocalMapping() is called
195   */
196   (*mapping)->globals = 0;
197   PetscFunctionReturn(0);
198 }
199 
200 #undef __FUNCT__
201 #define __FUNCT__ "ISLocalToGlobalMappingBlock"
202 /*@C
203     ISLocalToGlobalMappingBlock - Creates a blocked index version of an
204        ISLocalToGlobalMapping that is appropriate for MatSetLocalToGlobalMappingBlock()
205        and VecSetLocalToGlobalMappingBlock().
206 
207     Not Collective, but communicator may have more than one process
208 
209     Input Parameters:
210 +    inmap - original point-wise mapping
211 -    bs - block size
212 
213     Output Parameter:
214 .   outmap - block based mapping
215 
216     Level: advanced
217 
218     Concepts: mapping^local to global
219 
220 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate(), ISLocalToGlobalMappingCreateIS()
221 @*/
222 int ISLocalToGlobalMappingBlock(ISLocalToGlobalMapping inmap,int bs,ISLocalToGlobalMapping *outmap)
223 {
224   int ierr,*ii,i,n;
225 
226   PetscFunctionBegin;
227 
228   if (bs > 1) {
229     n    = inmap->n/bs;
230     ierr = PetscMalloc(n*sizeof(int),&ii);CHKERRQ(ierr);
231     for (i=0; i<n; i++) {
232       ii[i] = inmap->indices[bs*i]/bs;
233     }
234     ierr = ISLocalToGlobalMappingCreate(inmap->comm,n,ii,outmap);CHKERRQ(ierr);
235     ierr = PetscFree(ii);CHKERRQ(ierr);
236   } else {
237     *outmap = inmap;
238     ierr    = PetscObjectReference((PetscObject)inmap);CHKERRQ(ierr);
239   }
240   PetscFunctionReturn(0);
241 }
242 
243 #undef __FUNCT__
244 #define __FUNCT__ "ISLocalToGlobalMappingDestroy"
245 /*@
246    ISLocalToGlobalMappingDestroy - Destroys a mapping between a local (0 to n)
247    ordering and a global parallel ordering.
248 
249    Note Collective
250 
251    Input Parameters:
252 .  mapping - mapping data structure
253 
254    Level: advanced
255 
256 .seealso: ISLocalToGlobalMappingCreate()
257 @*/
258 int ISLocalToGlobalMappingDestroy(ISLocalToGlobalMapping mapping)
259 {
260   int ierr;
261   PetscFunctionBegin;
262   PetscValidPointer(mapping);
263   if (--mapping->refct > 0) PetscFunctionReturn(0);
264   if (mapping->refct < 0) {
265     SETERRQ(1,"Mapping already destroyed");
266   }
267 
268   ierr = PetscFree(mapping->indices);CHKERRQ(ierr);
269   if (mapping->globals) {ierr = PetscFree(mapping->globals);CHKERRQ(ierr);}
270   PetscLogObjectDestroy(mapping);
271   PetscHeaderDestroy(mapping);
272   PetscFunctionReturn(0);
273 }
274 
275 #undef __FUNCT__
276 #define __FUNCT__ "ISLocalToGlobalMappingApplyIS"
277 /*@
278     ISLocalToGlobalMappingApplyIS - Creates from an IS in the local numbering
279     a new index set using the global numbering defined in an ISLocalToGlobalMapping
280     context.
281 
282     Not collective
283 
284     Input Parameters:
285 +   mapping - mapping between local and global numbering
286 -   is - index set in local numbering
287 
288     Output Parameters:
289 .   newis - index set in global numbering
290 
291     Level: advanced
292 
293     Concepts: mapping^local to global
294 
295 .seealso: ISLocalToGlobalMappingApply(), ISLocalToGlobalMappingCreate(),
296           ISLocalToGlobalMappingDestroy(), ISGlobalToLocalMappingApply()
297 @*/
298 int ISLocalToGlobalMappingApplyIS(ISLocalToGlobalMapping mapping,IS is,IS *newis)
299 {
300   int ierr,n,i,*idxin,*idxmap,*idxout,Nmax = mapping->n;
301 
302   PetscFunctionBegin;
303   PetscValidPointer(mapping);
304   PetscValidHeaderSpecific(is,IS_COOKIE);
305   PetscValidPointer(newis);
306 
307   ierr   = ISGetLocalSize(is,&n);CHKERRQ(ierr);
308   ierr   = ISGetIndices(is,&idxin);CHKERRQ(ierr);
309   idxmap = mapping->indices;
310 
311   ierr = PetscMalloc((n+1)*sizeof(int),&idxout);CHKERRQ(ierr);
312   for (i=0; i<n; i++) {
313     if (idxin[i] >= Nmax) SETERRQ3(PETSC_ERR_ARG_OUTOFRANGE,"Local index %d too large %d (max) at %d",idxin[i],Nmax,i);
314     idxout[i] = idxmap[idxin[i]];
315   }
316   ierr = ISRestoreIndices(is,&idxin);CHKERRQ(ierr);
317   ierr = ISCreateGeneral(PETSC_COMM_SELF,n,idxout,newis);CHKERRQ(ierr);
318   ierr = PetscFree(idxout);CHKERRQ(ierr);
319   PetscFunctionReturn(0);
320 }
321 
322 /*MC
323    ISLocalToGlobalMappingApply - Takes a list of integers in a local numbering
324    and converts them to the global numbering.
325 
326    Not collective
327 
328    Input Parameters:
329 +  mapping - the local to global mapping context
330 .  N - number of integers
331 -  in - input indices in local numbering
332 
333    Output Parameter:
334 .  out - indices in global numbering
335 
336    Synopsis:
337    int ISLocalToGlobalMappingApply(ISLocalToGlobalMapping mapping,int N,int in[],int out[])
338 
339    Notes:
340    The in and out array parameters may be identical.
341 
342    Level: advanced
343 
344 .seealso: ISLocalToGlobalMappingCreate(),ISLocalToGlobalMappingDestroy(),
345           ISLocalToGlobalMappingApplyIS(),AOCreateBasic(),AOApplicationToPetsc(),
346           AOPetscToApplication(), ISGlobalToLocalMappingApply()
347 
348     Concepts: mapping^local to global
349 
350 M*/
351 
352 /* -----------------------------------------------------------------------------------------*/
353 
354 #undef __FUNCT__
355 #define __FUNCT__ "ISGlobalToLocalMappingSetUp_Private"
356 /*
357     Creates the global fields in the ISLocalToGlobalMapping structure
358 */
359 static int ISGlobalToLocalMappingSetUp_Private(ISLocalToGlobalMapping mapping)
360 {
361   int ierr,i,*idx = mapping->indices,n = mapping->n,end,start,*globals;
362 
363   PetscFunctionBegin;
364   end   = 0;
365   start = 100000000;
366 
367   for (i=0; i<n; i++) {
368     if (idx[i] < 0) continue;
369     if (idx[i] < start) start = idx[i];
370     if (idx[i] > end)   end   = idx[i];
371   }
372   if (start > end) {start = 0; end = -1;}
373   mapping->globalstart = start;
374   mapping->globalend   = end;
375 
376   ierr             = PetscMalloc((end-start+2)*sizeof(int),&globals);CHKERRQ(ierr);
377   mapping->globals = globals;
378   for (i=0; i<end-start+1; i++) {
379     globals[i] = -1;
380   }
381   for (i=0; i<n; i++) {
382     if (idx[i] < 0) continue;
383     globals[idx[i] - start] = i;
384   }
385 
386   PetscLogObjectMemory(mapping,(end-start+1)*sizeof(int));
387   PetscFunctionReturn(0);
388 }
389 
390 #undef __FUNCT__
391 #define __FUNCT__ "ISGlobalToLocalMappingApply"
392 /*@
393     ISGlobalToLocalMappingApply - Provides the local numbering for a list of integers
394     specified with a global numbering.
395 
396     Not collective
397 
398     Input Parameters:
399 +   mapping - mapping between local and global numbering
400 .   type - IS_GTOLM_MASK - replaces global indices with no local value with -1
401            IS_GTOLM_DROP - drops the indices with no local value from the output list
402 .   n - number of global indices to map
403 -   idx - global indices to map
404 
405     Output Parameters:
406 +   nout - number of indices in output array (if type == IS_GTOLM_MASK then nout = n)
407 -   idxout - local index of each global index, one must pass in an array long enough
408              to hold all the indices. You can call ISGlobalToLocalMappingApply() with
409              idxout == PETSC_NULL to determine the required length (returned in nout)
410              and then allocate the required space and call ISGlobalToLocalMappingApply()
411              a second time to set the values.
412 
413     Notes:
414     Either nout or idxout may be PETSC_NULL. idx and idxout may be identical.
415 
416     This is not scalable in memory usage. Each processor requires O(Nglobal) size
417     array to compute these.
418 
419     Level: advanced
420 
421     Concepts: mapping^global to local
422 
423 .seealso: ISLocalToGlobalMappingApply(), ISLocalToGlobalMappingCreate(),
424           ISLocalToGlobalMappingDestroy()
425 @*/
426 int ISGlobalToLocalMappingApply(ISLocalToGlobalMapping mapping,ISGlobalToLocalMappingType type,
427                                   int n,const int idx[],int *nout,int idxout[])
428 {
429   int i,ierr,*globals,nf = 0,tmp,start,end;
430 
431   PetscFunctionBegin;
432   if (!mapping->globals) {
433     ierr = ISGlobalToLocalMappingSetUp_Private(mapping);CHKERRQ(ierr);
434   }
435   globals = mapping->globals;
436   start   = mapping->globalstart;
437   end     = mapping->globalend;
438 
439   if (type == IS_GTOLM_MASK) {
440     if (idxout) {
441       for (i=0; i<n; i++) {
442         if (idx[i] < 0) idxout[i] = idx[i];
443         else if (idx[i] < start) idxout[i] = -1;
444         else if (idx[i] > end)   idxout[i] = -1;
445         else                     idxout[i] = globals[idx[i] - start];
446       }
447     }
448     if (nout) *nout = n;
449   } else {
450     if (idxout) {
451       for (i=0; i<n; i++) {
452         if (idx[i] < 0) continue;
453         if (idx[i] < start) continue;
454         if (idx[i] > end) continue;
455         tmp = globals[idx[i] - start];
456         if (tmp < 0) continue;
457         idxout[nf++] = tmp;
458       }
459     } else {
460       for (i=0; i<n; i++) {
461         if (idx[i] < 0) continue;
462         if (idx[i] < start) continue;
463         if (idx[i] > end) continue;
464         tmp = globals[idx[i] - start];
465         if (tmp < 0) continue;
466         nf++;
467       }
468     }
469     if (nout) *nout = nf;
470   }
471 
472   PetscFunctionReturn(0);
473 }
474 
475 #undef __FUNCT__
476 #define __FUNCT__ "ISLocalToGlobalMappingGetInfo"
477 /*@C
478     ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each processor and
479      each index shared by more than one processor
480 
481     Collective on ISLocalToGlobalMapping
482 
483     Input Parameters:
484 .   mapping - the mapping from local to global indexing
485 
486     Output Parameter:
487 +   nproc - number of processors that are connected to this one
488 .   proc - neighboring processors
489 .   numproc - number of indices for each subdomain (processor)
490 -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
491 
492     Level: advanced
493 
494     Concepts: mapping^local to global
495 
496 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate(),
497           ISLocalToGlobalMappingRestoreInfo()
498 @*/
499 int ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping,int *nproc,int **procs,int **numprocs,int ***indices)
500 {
501   int         i,n = mapping->n,ierr,Ng,ng,max = 0,*lindices = mapping->indices;
502   int         size,rank,*nprocs,*owner,nsends,*sends,j,*starts,*work,nmax,nrecvs,*recvs,proc;
503   int         tag1,tag2,tag3,cnt,*len,*source,imdex,scale,*ownedsenders,*nownedsenders,rstart,nowned;
504   int         node,nownedm,nt,*sends2,nsends2,*starts2,*lens2,*dest,nrecvs2,*starts3,*recvs2,k,*bprocs,*tmp;
505   int         first_procs,first_numprocs,*first_indices;
506   MPI_Request *recv_waits,*send_waits;
507   MPI_Status  recv_status,*send_status,*recv_statuses;
508   MPI_Comm    comm = mapping->comm;
509   PetscTruth  debug = PETSC_FALSE;
510 
511   PetscFunctionBegin;
512   ierr   = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
513   ierr   = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
514   if (size == 1) {
515     *nproc         = 0;
516     *procs         = PETSC_NULL;
517     ierr           = PetscMalloc(sizeof(int),numprocs);CHKERRQ(ierr);
518     (*numprocs)[0] = 0;
519     ierr           = PetscMalloc(sizeof(int*),indices);CHKERRQ(ierr);
520     (*indices)[0]  = PETSC_NULL;
521     PetscFunctionReturn(0);
522   }
523 
524   ierr = PetscOptionsHasName(PETSC_NULL,"-islocaltoglobalmappinggetinfo_debug",&debug);CHKERRQ(ierr);
525 
526   /*
527     Notes on ISLocalToGlobalMappingGetInfo
528 
529     globally owned node - the nodes that have been assigned to this processor in global
530            numbering, just for this routine.
531 
532     nontrivial globally owned node - node assigned to this processor that is on a subdomain
533            boundary (i.e. is has more than one local owner)
534 
535     locally owned node - node that exists on this processors subdomain
536 
537     nontrivial locally owned node - node that is not in the interior (i.e. has more than one
538            local subdomain
539   */
540   ierr = PetscObjectGetNewTag((PetscObject)mapping,&tag1);CHKERRQ(ierr);
541   ierr = PetscObjectGetNewTag((PetscObject)mapping,&tag2);CHKERRQ(ierr);
542   ierr = PetscObjectGetNewTag((PetscObject)mapping,&tag3);CHKERRQ(ierr);
543 
544   for (i=0; i<n; i++) {
545     if (lindices[i] > max) max = lindices[i];
546   }
547   ierr   = MPI_Allreduce(&max,&Ng,1,MPI_INT,MPI_MAX,comm);CHKERRQ(ierr);
548   Ng++;
549   ierr   = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
550   ierr   = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
551   scale  = Ng/size + 1;
552   ng     = scale; if (rank == size-1) ng = Ng - scale*(size-1); ng = PetscMax(1,ng);
553   rstart = scale*rank;
554 
555   /* determine ownership ranges of global indices */
556   ierr = PetscMalloc((2*size+1)*sizeof(int),&nprocs);CHKERRQ(ierr);
557   ierr = PetscMemzero(nprocs,2*size*sizeof(int));CHKERRQ(ierr);
558 
559   /* determine owners of each local node  */
560   ierr = PetscMalloc((n+1)*sizeof(int),&owner);CHKERRQ(ierr);
561   for (i=0; i<n; i++) {
562     proc              = lindices[i]/scale; /* processor that globally owns this index */
563     nprocs[size+proc] = 1;                 /* processor globally owns at least one of ours */
564     owner[i]          = proc;
565     nprocs[proc]++;                        /* count of how many that processor globally owns of ours */
566   }
567   nsends = 0; for (i=0; i<size; i++) nsends += nprocs[size + i];
568   PetscLogInfo(0,"ISLocalToGlobalMappingGetInfo: Number of global owners for my local data %d\n",nsends);
569 
570   /* inform other processors of number of messages and max length*/
571   ierr = PetscMalloc(2*size*sizeof(int),&work);CHKERRQ(ierr);
572   ierr   = MPI_Allreduce(nprocs,work,2*size,MPI_INT,PetscMaxSum_Op,comm);CHKERRQ(ierr);
573   nmax   = work[rank];
574   nrecvs = work[size+rank];
575   ierr   = PetscFree(work);CHKERRQ(ierr);
576   PetscLogInfo(0,"ISLocalToGlobalMappingGetInfo: Number of local owners for my global data %d\n",nrecvs);
577 
578   /* post receives for owned rows */
579   ierr = PetscMalloc((2*nrecvs+1)*(nmax+1)*sizeof(int),&recvs);CHKERRQ(ierr);
580   ierr = PetscMalloc((nrecvs+1)*sizeof(MPI_Request),&recv_waits);CHKERRQ(ierr);
581   for (i=0; i<nrecvs; i++) {
582     ierr = MPI_Irecv(recvs+2*nmax*i,2*nmax,MPI_INT,MPI_ANY_SOURCE,tag1,comm,recv_waits+i);CHKERRQ(ierr);
583   }
584 
585   /* pack messages containing lists of local nodes to owners */
586   ierr       = PetscMalloc((2*n+1)*sizeof(int),&sends);CHKERRQ(ierr);
587   ierr       = PetscMalloc((size+1)*sizeof(int),&starts);CHKERRQ(ierr);
588   starts[0]  = 0;
589   for (i=1; i<size; i++) { starts[i] = starts[i-1] + 2*nprocs[i-1];}
590   for (i=0; i<n; i++) {
591     sends[starts[owner[i]]++] = lindices[i];
592     sends[starts[owner[i]]++] = i;
593   }
594   ierr = PetscFree(owner);CHKERRQ(ierr);
595   starts[0]  = 0;
596   for (i=1; i<size; i++) { starts[i] = starts[i-1] + 2*nprocs[i-1];}
597 
598   /* send the messages */
599   ierr = PetscMalloc((nsends+1)*sizeof(MPI_Request),&send_waits);CHKERRQ(ierr);
600   ierr = PetscMalloc((nsends+1)*sizeof(int),&dest);CHKERRQ(ierr);
601   cnt = 0;
602   for (i=0; i<size; i++) {
603     if (nprocs[i]) {
604       ierr      = MPI_Isend(sends+starts[i],2*nprocs[i],MPI_INT,i,tag1,comm,send_waits+cnt);CHKERRQ(ierr);
605       dest[cnt] = i;
606       cnt++;
607     }
608   }
609   ierr = PetscFree(starts);CHKERRQ(ierr);
610 
611   /* wait on receives */
612   ierr = PetscMalloc((2*nrecvs+1)*sizeof(int),&source);CHKERRQ(ierr);
613   len  = source + nrecvs;
614   cnt  = nrecvs;
615   ierr = PetscMalloc((ng+1)*sizeof(int),&nownedsenders);CHKERRQ(ierr);
616   ierr = PetscMemzero(nownedsenders,ng*sizeof(int));CHKERRQ(ierr);
617   while (cnt) {
618     ierr = MPI_Waitany(nrecvs,recv_waits,&imdex,&recv_status);CHKERRQ(ierr);
619     /* unpack receives into our local space */
620     ierr           = MPI_Get_count(&recv_status,MPI_INT,&len[imdex]);CHKERRQ(ierr);
621     source[imdex]  = recv_status.MPI_SOURCE;
622     len[imdex]     = len[imdex]/2;
623     /* count how many local owners for each of my global owned indices */
624     for (i=0; i<len[imdex]; i++) nownedsenders[recvs[2*imdex*nmax+2*i]-rstart]++;
625     cnt--;
626   }
627   ierr = PetscFree(recv_waits);CHKERRQ(ierr);
628 
629   /* count how many globally owned indices are on an edge multiplied by how many processors own them. */
630   nowned  = 0;
631   nownedm = 0;
632   for (i=0; i<ng; i++) {
633     if (nownedsenders[i] > 1) {nownedm += nownedsenders[i]; nowned++;}
634   }
635 
636   /* create single array to contain rank of all local owners of each globally owned index */
637   ierr      = PetscMalloc((nownedm+1)*sizeof(int),&ownedsenders);CHKERRQ(ierr);
638   ierr      = PetscMalloc((ng+1)*sizeof(int),&starts);CHKERRQ(ierr);
639   starts[0] = 0;
640   for (i=1; i<ng; i++) {
641     if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
642     else starts[i] = starts[i-1];
643   }
644 
645   /* for each nontrival globally owned node list all arriving processors */
646   for (i=0; i<nrecvs; i++) {
647     for (j=0; j<len[i]; j++) {
648       node = recvs[2*i*nmax+2*j]-rstart;
649       if (nownedsenders[node] > 1) {
650         ownedsenders[starts[node]++] = source[i];
651       }
652     }
653   }
654 
655   if (debug) { /* -----------------------------------  */
656     starts[0]    = 0;
657     for (i=1; i<ng; i++) {
658       if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
659       else starts[i] = starts[i-1];
660     }
661     for (i=0; i<ng; i++) {
662       if (nownedsenders[i] > 1) {
663         ierr = PetscSynchronizedPrintf(comm,"[%d] global node %d local owner processors: ",rank,i+rstart);CHKERRQ(ierr);
664         for (j=0; j<nownedsenders[i]; j++) {
665           ierr = PetscSynchronizedPrintf(comm,"%d ",ownedsenders[starts[i]+j]);CHKERRQ(ierr);
666         }
667         ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
668       }
669     }
670     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
671   }/* -----------------------------------  */
672 
673   /* wait on original sends */
674   if (nsends) {
675     ierr = PetscMalloc(nsends*sizeof(MPI_Status),&send_status);CHKERRQ(ierr);
676     ierr = MPI_Waitall(nsends,send_waits,send_status);CHKERRQ(ierr);
677     ierr = PetscFree(send_status);CHKERRQ(ierr);
678   }
679   ierr = PetscFree(send_waits);CHKERRQ(ierr);
680   ierr = PetscFree(sends);CHKERRQ(ierr);
681   ierr = PetscFree(nprocs);CHKERRQ(ierr);
682 
683   /* pack messages to send back to local owners */
684   starts[0]    = 0;
685   for (i=1; i<ng; i++) {
686     if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
687     else starts[i] = starts[i-1];
688   }
689   nsends2 = nrecvs;
690   ierr    = PetscMalloc((nsends2+1)*sizeof(int),&nprocs);CHKERRQ(ierr); /* length of each message */
691   for (i=0; i<nrecvs; i++) {
692     nprocs[i] = 1;
693     for (j=0; j<len[i]; j++) {
694       node = recvs[2*i*nmax+2*j]-rstart;
695       if (nownedsenders[node] > 1) {
696         nprocs[i] += 2 + nownedsenders[node];
697       }
698     }
699   }
700   nt = 0; for (i=0; i<nsends2; i++) nt += nprocs[i];
701   ierr = PetscMalloc((nt+1)*sizeof(int),&sends2);CHKERRQ(ierr);
702   ierr = PetscMalloc((nsends2+1)*sizeof(int),&starts2);CHKERRQ(ierr);
703   starts2[0] = 0; for (i=1; i<nsends2; i++) starts2[i] = starts2[i-1] + nprocs[i-1];
704   /*
705      Each message is 1 + nprocs[i] long, and consists of
706        (0) the number of nodes being sent back
707        (1) the local node number,
708        (2) the number of processors sharing it,
709        (3) the processors sharing it
710   */
711   for (i=0; i<nsends2; i++) {
712     cnt = 1;
713     sends2[starts2[i]] = 0;
714     for (j=0; j<len[i]; j++) {
715       node = recvs[2*i*nmax+2*j]-rstart;
716       if (nownedsenders[node] > 1) {
717         sends2[starts2[i]]++;
718         sends2[starts2[i]+cnt++] = recvs[2*i*nmax+2*j+1];
719         sends2[starts2[i]+cnt++] = nownedsenders[node];
720         ierr = PetscMemcpy(&sends2[starts2[i]+cnt],&ownedsenders[starts[node]],nownedsenders[node]*sizeof(int));CHKERRQ(ierr);
721         cnt += nownedsenders[node];
722       }
723     }
724   }
725 
726   /* send the message lengths */
727   for (i=0; i<nsends2; i++) {
728     ierr = MPI_Send(&nprocs[i],1,MPI_INT,source[i],tag2,comm);CHKERRQ(ierr);
729   }
730 
731   /* receive the message lengths */
732   nrecvs2 = nsends;
733   ierr = PetscMalloc((nrecvs2+1)*sizeof(int),&lens2);CHKERRQ(ierr);
734   ierr = PetscMalloc((nrecvs2+1)*sizeof(int),&starts3);CHKERRQ(ierr);
735   nt      = 0;
736   for (i=0; i<nrecvs2; i++) {
737     ierr =  MPI_Recv(&lens2[i],1,MPI_INT,dest[i],tag2,comm,&recv_status);CHKERRQ(ierr);
738     nt   += lens2[i];
739   }
740   starts3[0] = 0;
741   for (i=0; i<nrecvs2-1; i++) {
742     starts3[i+1] = starts3[i] + lens2[i];
743   }
744   ierr = PetscMalloc((nt+1)*sizeof(int),&recvs2);CHKERRQ(ierr);
745   ierr = PetscMalloc((nrecvs2+1)*sizeof(MPI_Request),&recv_waits);CHKERRQ(ierr);
746   for (i=0; i<nrecvs2; i++) {
747     ierr = MPI_Irecv(recvs2+starts3[i],lens2[i],MPI_INT,dest[i],tag3,comm,recv_waits+i);CHKERRQ(ierr);
748   }
749 
750   /* send the messages */
751   ierr = PetscMalloc((nsends2+1)*sizeof(MPI_Request),&send_waits);CHKERRQ(ierr);
752   for (i=0; i<nsends2; i++) {
753     ierr = MPI_Isend(sends2+starts2[i],nprocs[i],MPI_INT,source[i],tag3,comm,send_waits+i);CHKERRQ(ierr);
754   }
755 
756   /* wait on receives */
757   ierr = PetscMalloc((nrecvs2+1)*sizeof(MPI_Status),&recv_statuses);CHKERRQ(ierr);
758   ierr = MPI_Waitall(nrecvs2,recv_waits,recv_statuses);CHKERRQ(ierr);
759   ierr = PetscFree(recv_statuses);CHKERRQ(ierr);
760   ierr = PetscFree(recv_waits);CHKERRQ(ierr);
761   ierr = PetscFree(nprocs);CHKERRQ(ierr);
762 
763   if (debug) { /* -----------------------------------  */
764     cnt = 0;
765     for (i=0; i<nrecvs2; i++) {
766       nt = recvs2[cnt++];
767       for (j=0; j<nt; j++) {
768         ierr = PetscSynchronizedPrintf(comm,"[%d] local node %d number of subdomains %d: ",rank,recvs2[cnt],recvs2[cnt+1]);CHKERRQ(ierr);
769         for (k=0; k<recvs2[cnt+1]; k++) {
770           ierr = PetscSynchronizedPrintf(comm,"%d ",recvs2[cnt+2+k]);CHKERRQ(ierr);
771         }
772         cnt += 2 + recvs2[cnt+1];
773         ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
774       }
775     }
776     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
777   } /* -----------------------------------  */
778 
779   /* count number subdomains for each local node */
780   ierr = PetscMalloc(size*sizeof(int),&nprocs);CHKERRQ(ierr);
781   ierr = PetscMemzero(nprocs,size*sizeof(int));CHKERRQ(ierr);
782   cnt  = 0;
783   for (i=0; i<nrecvs2; i++) {
784     nt = recvs2[cnt++];
785     for (j=0; j<nt; j++) {
786       for (k=0; k<recvs2[cnt+1]; k++) {
787         nprocs[recvs2[cnt+2+k]]++;
788       }
789       cnt += 2 + recvs2[cnt+1];
790     }
791   }
792   nt = 0; for (i=0; i<size; i++) nt += (nprocs[i] > 0);
793   *nproc    = nt;
794   ierr = PetscMalloc((nt+1)*sizeof(int),procs);CHKERRQ(ierr);
795   ierr = PetscMalloc((nt+1)*sizeof(int),numprocs);CHKERRQ(ierr);
796   ierr = PetscMalloc((nt+1)*sizeof(int*),indices);CHKERRQ(ierr);
797   ierr = PetscMalloc(size*sizeof(int),&bprocs);CHKERRQ(ierr);
798   cnt       = 0;
799   for (i=0; i<size; i++) {
800     if (nprocs[i] > 0) {
801       bprocs[i]        = cnt;
802       (*procs)[cnt]    = i;
803       (*numprocs)[cnt] = nprocs[i];
804       ierr             = PetscMalloc(nprocs[i]*sizeof(int),&(*indices)[cnt]);CHKERRQ(ierr);
805       cnt++;
806     }
807   }
808 
809   /* make the list of subdomains for each nontrivial local node */
810   ierr = PetscMemzero(*numprocs,nt*sizeof(int));CHKERRQ(ierr);
811   cnt  = 0;
812   for (i=0; i<nrecvs2; i++) {
813     nt = recvs2[cnt++];
814     for (j=0; j<nt; j++) {
815       for (k=0; k<recvs2[cnt+1]; k++) {
816         (*indices)[bprocs[recvs2[cnt+2+k]]][(*numprocs)[bprocs[recvs2[cnt+2+k]]]++] = recvs2[cnt];
817       }
818       cnt += 2 + recvs2[cnt+1];
819     }
820   }
821   ierr = PetscFree(bprocs);CHKERRQ(ierr);
822   ierr = PetscFree(recvs2);CHKERRQ(ierr);
823 
824   /* sort the node indexing by their global numbers */
825   nt = *nproc;
826   for (i=0; i<nt; i++) {
827     ierr = PetscMalloc(((*numprocs)[i])*sizeof(int),&tmp);CHKERRQ(ierr);
828     for (j=0; j<(*numprocs)[i]; j++) {
829       tmp[j] = lindices[(*indices)[i][j]];
830     }
831     ierr = PetscSortIntWithArray((*numprocs)[i],tmp,(*indices)[i]);CHKERRQ(ierr);
832     ierr = PetscFree(tmp);CHKERRQ(ierr);
833   }
834 
835   if (debug) { /* -----------------------------------  */
836     nt = *nproc;
837     for (i=0; i<nt; i++) {
838       ierr = PetscSynchronizedPrintf(comm,"[%d] subdomain %d number of indices %d: ",rank,(*procs)[i],(*numprocs)[i]);CHKERRQ(ierr);
839       for (j=0; j<(*numprocs)[i]; j++) {
840         ierr = PetscSynchronizedPrintf(comm,"%d ",(*indices)[i][j]);CHKERRQ(ierr);
841       }
842       ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
843     }
844     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
845   } /* -----------------------------------  */
846 
847   /* wait on sends */
848   if (nsends2) {
849     ierr = PetscMalloc(nsends2*sizeof(MPI_Status),&send_status);CHKERRQ(ierr);
850     ierr = MPI_Waitall(nsends2,send_waits,send_status);CHKERRQ(ierr);
851     ierr = PetscFree(send_status);CHKERRQ(ierr);
852   }
853 
854   ierr = PetscFree(starts3);CHKERRQ(ierr);
855   ierr = PetscFree(dest);CHKERRQ(ierr);
856   ierr = PetscFree(send_waits);CHKERRQ(ierr);
857 
858   ierr = PetscFree(nownedsenders);CHKERRQ(ierr);
859   ierr = PetscFree(ownedsenders);CHKERRQ(ierr);
860   ierr = PetscFree(starts);CHKERRQ(ierr);
861   ierr = PetscFree(starts2);CHKERRQ(ierr);
862   ierr = PetscFree(lens2);CHKERRQ(ierr);
863 
864   ierr = PetscFree(source);CHKERRQ(ierr);
865   ierr = PetscFree(recvs);CHKERRQ(ierr);
866   ierr = PetscFree(nprocs);CHKERRQ(ierr);
867   ierr = PetscFree(sends2);CHKERRQ(ierr);
868 
869   /* put the information about myself as the first entry in the list */
870   first_procs    = (*procs)[0];
871   first_numprocs = (*numprocs)[0];
872   first_indices  = (*indices)[0];
873   for (i=0; i<*nproc; i++) {
874     if ((*procs)[i] == rank) {
875       (*procs)[0]    = (*procs)[i];
876       (*numprocs)[0] = (*numprocs)[i];
877       (*indices)[0]  = (*indices)[i];
878       (*procs)[i]    = first_procs;
879       (*numprocs)[i] = first_numprocs;
880       (*indices)[i]  = first_indices;
881       break;
882     }
883   }
884 
885   PetscFunctionReturn(0);
886 }
887 
888 #undef __FUNCT__
889 #define __FUNCT__ "ISLocalToGlobalMappingRestoreInfo"
890 /*@C
891     ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by ISLocalToGlobalMappingGetInfo()
892 
893     Collective on ISLocalToGlobalMapping
894 
895     Input Parameters:
896 .   mapping - the mapping from local to global indexing
897 
898     Output Parameter:
899 +   nproc - number of processors that are connected to this one
900 .   proc - neighboring processors
901 .   numproc - number of indices for each processor
902 -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
903 
904     Level: advanced
905 
906 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate(),
907           ISLocalToGlobalMappingGetInfo()
908 @*/
909 int ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping,int *nproc,int **procs,int **numprocs,int ***indices)
910 {
911   int ierr,i;
912 
913   PetscFunctionBegin;
914   if (*procs) {ierr = PetscFree(*procs);CHKERRQ(ierr);}
915   if (*numprocs) {ierr = PetscFree(*numprocs);CHKERRQ(ierr);}
916   if (*indices) {
917     if ((*indices)[0]) {ierr = PetscFree((*indices)[0]);CHKERRQ(ierr);}
918     for (i=1; i<*nproc; i++) {
919       if ((*indices)[i]) {ierr = PetscFree((*indices)[i]);CHKERRQ(ierr);}
920     }
921     ierr = PetscFree(*indices);CHKERRQ(ierr);
922   }
923   PetscFunctionReturn(0);
924 }
925 
926 
927 
928 
929 
930 
931 
932 
933 
934 
935 
936 
937 
938 
939 
940 
941 
942 
943