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