xref: /petsc/src/vec/is/utils/isltog.c (revision db2f66daa1e68431584f92b2fd1bb745b78c0911)
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,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[2*proc+1] = 1;                 /* processor globally owns at least one of ours */
564     owner[i]         = proc;
565     nprocs[2*proc]++;                     /* count of how many that processor globally owns of ours */
566   }
567   nsends = 0; for (i=0; i<size; i++) nsends += nprocs[2*i+1];
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 = PetscMaxSum(comm,nprocs,&nmax,&nrecvs);CHKERRQ(ierr);
572   PetscLogInfo(0,"ISLocalToGlobalMappingGetInfo: Number of local owners for my global data %d\n",nrecvs);
573 
574   /* post receives for owned rows */
575   ierr = PetscMalloc((2*nrecvs+1)*(nmax+1)*sizeof(int),&recvs);CHKERRQ(ierr);
576   ierr = PetscMalloc((nrecvs+1)*sizeof(MPI_Request),&recv_waits);CHKERRQ(ierr);
577   for (i=0; i<nrecvs; i++) {
578     ierr = MPI_Irecv(recvs+2*nmax*i,2*nmax,MPI_INT,MPI_ANY_SOURCE,tag1,comm,recv_waits+i);CHKERRQ(ierr);
579   }
580 
581   /* pack messages containing lists of local nodes to owners */
582   ierr       = PetscMalloc((2*n+1)*sizeof(int),&sends);CHKERRQ(ierr);
583   ierr       = PetscMalloc((size+1)*sizeof(int),&starts);CHKERRQ(ierr);
584   starts[0]  = 0;
585   for (i=1; i<size; i++) { starts[i] = starts[i-1] + 2*nprocs[2*i-2];}
586   for (i=0; i<n; i++) {
587     sends[starts[owner[i]]++] = lindices[i];
588     sends[starts[owner[i]]++] = i;
589   }
590   ierr = PetscFree(owner);CHKERRQ(ierr);
591   starts[0]  = 0;
592   for (i=1; i<size; i++) { starts[i] = starts[i-1] + 2*nprocs[2*i-2];}
593 
594   /* send the messages */
595   ierr = PetscMalloc((nsends+1)*sizeof(MPI_Request),&send_waits);CHKERRQ(ierr);
596   ierr = PetscMalloc((nsends+1)*sizeof(int),&dest);CHKERRQ(ierr);
597   cnt = 0;
598   for (i=0; i<size; i++) {
599     if (nprocs[2*i]) {
600       ierr      = MPI_Isend(sends+starts[i],2*nprocs[2*i],MPI_INT,i,tag1,comm,send_waits+cnt);CHKERRQ(ierr);
601       dest[cnt] = i;
602       cnt++;
603     }
604   }
605   ierr = PetscFree(starts);CHKERRQ(ierr);
606 
607   /* wait on receives */
608   ierr = PetscMalloc((2*nrecvs+1)*sizeof(int),&source);CHKERRQ(ierr);
609   len  = source + nrecvs;
610   cnt  = nrecvs;
611   ierr = PetscMalloc((ng+1)*sizeof(int),&nownedsenders);CHKERRQ(ierr);
612   ierr = PetscMemzero(nownedsenders,ng*sizeof(int));CHKERRQ(ierr);
613   while (cnt) {
614     ierr = MPI_Waitany(nrecvs,recv_waits,&imdex,&recv_status);CHKERRQ(ierr);
615     /* unpack receives into our local space */
616     ierr           = MPI_Get_count(&recv_status,MPI_INT,&len[imdex]);CHKERRQ(ierr);
617     source[imdex]  = recv_status.MPI_SOURCE;
618     len[imdex]     = len[imdex]/2;
619     /* count how many local owners for each of my global owned indices */
620     for (i=0; i<len[imdex]; i++) nownedsenders[recvs[2*imdex*nmax+2*i]-rstart]++;
621     cnt--;
622   }
623   ierr = PetscFree(recv_waits);CHKERRQ(ierr);
624 
625   /* count how many globally owned indices are on an edge multiplied by how many processors own them. */
626   nowned  = 0;
627   nownedm = 0;
628   for (i=0; i<ng; i++) {
629     if (nownedsenders[i] > 1) {nownedm += nownedsenders[i]; nowned++;}
630   }
631 
632   /* create single array to contain rank of all local owners of each globally owned index */
633   ierr      = PetscMalloc((nownedm+1)*sizeof(int),&ownedsenders);CHKERRQ(ierr);
634   ierr      = PetscMalloc((ng+1)*sizeof(int),&starts);CHKERRQ(ierr);
635   starts[0] = 0;
636   for (i=1; i<ng; i++) {
637     if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
638     else starts[i] = starts[i-1];
639   }
640 
641   /* for each nontrival globally owned node list all arriving processors */
642   for (i=0; i<nrecvs; i++) {
643     for (j=0; j<len[i]; j++) {
644       node = recvs[2*i*nmax+2*j]-rstart;
645       if (nownedsenders[node] > 1) {
646         ownedsenders[starts[node]++] = source[i];
647       }
648     }
649   }
650 
651   if (debug) { /* -----------------------------------  */
652     starts[0]    = 0;
653     for (i=1; i<ng; i++) {
654       if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
655       else starts[i] = starts[i-1];
656     }
657     for (i=0; i<ng; i++) {
658       if (nownedsenders[i] > 1) {
659         ierr = PetscSynchronizedPrintf(comm,"[%d] global node %d local owner processors: ",rank,i+rstart);CHKERRQ(ierr);
660         for (j=0; j<nownedsenders[i]; j++) {
661           ierr = PetscSynchronizedPrintf(comm,"%d ",ownedsenders[starts[i]+j]);CHKERRQ(ierr);
662         }
663         ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
664       }
665     }
666     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
667   }/* -----------------------------------  */
668 
669   /* wait on original sends */
670   if (nsends) {
671     ierr = PetscMalloc(nsends*sizeof(MPI_Status),&send_status);CHKERRQ(ierr);
672     ierr = MPI_Waitall(nsends,send_waits,send_status);CHKERRQ(ierr);
673     ierr = PetscFree(send_status);CHKERRQ(ierr);
674   }
675   ierr = PetscFree(send_waits);CHKERRQ(ierr);
676   ierr = PetscFree(sends);CHKERRQ(ierr);
677   ierr = PetscFree(nprocs);CHKERRQ(ierr);
678 
679   /* pack messages to send back to local owners */
680   starts[0]    = 0;
681   for (i=1; i<ng; i++) {
682     if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
683     else starts[i] = starts[i-1];
684   }
685   nsends2 = nrecvs;
686   ierr    = PetscMalloc((nsends2+1)*sizeof(int),&nprocs);CHKERRQ(ierr); /* length of each message */
687   for (i=0; i<nrecvs; i++) {
688     nprocs[i] = 1;
689     for (j=0; j<len[i]; j++) {
690       node = recvs[2*i*nmax+2*j]-rstart;
691       if (nownedsenders[node] > 1) {
692         nprocs[i] += 2 + nownedsenders[node];
693       }
694     }
695   }
696   nt = 0; for (i=0; i<nsends2; i++) nt += nprocs[i];
697   ierr = PetscMalloc((nt+1)*sizeof(int),&sends2);CHKERRQ(ierr);
698   ierr = PetscMalloc((nsends2+1)*sizeof(int),&starts2);CHKERRQ(ierr);
699   starts2[0] = 0; for (i=1; i<nsends2; i++) starts2[i] = starts2[i-1] + nprocs[i-1];
700   /*
701      Each message is 1 + nprocs[i] long, and consists of
702        (0) the number of nodes being sent back
703        (1) the local node number,
704        (2) the number of processors sharing it,
705        (3) the processors sharing it
706   */
707   for (i=0; i<nsends2; i++) {
708     cnt = 1;
709     sends2[starts2[i]] = 0;
710     for (j=0; j<len[i]; j++) {
711       node = recvs[2*i*nmax+2*j]-rstart;
712       if (nownedsenders[node] > 1) {
713         sends2[starts2[i]]++;
714         sends2[starts2[i]+cnt++] = recvs[2*i*nmax+2*j+1];
715         sends2[starts2[i]+cnt++] = nownedsenders[node];
716         ierr = PetscMemcpy(&sends2[starts2[i]+cnt],&ownedsenders[starts[node]],nownedsenders[node]*sizeof(int));CHKERRQ(ierr);
717         cnt += nownedsenders[node];
718       }
719     }
720   }
721 
722   /* send the message lengths */
723   for (i=0; i<nsends2; i++) {
724     ierr = MPI_Send(&nprocs[i],1,MPI_INT,source[i],tag2,comm);CHKERRQ(ierr);
725   }
726 
727   /* receive the message lengths */
728   nrecvs2 = nsends;
729   ierr = PetscMalloc((nrecvs2+1)*sizeof(int),&lens2);CHKERRQ(ierr);
730   ierr = PetscMalloc((nrecvs2+1)*sizeof(int),&starts3);CHKERRQ(ierr);
731   nt      = 0;
732   for (i=0; i<nrecvs2; i++) {
733     ierr =  MPI_Recv(&lens2[i],1,MPI_INT,dest[i],tag2,comm,&recv_status);CHKERRQ(ierr);
734     nt   += lens2[i];
735   }
736   starts3[0] = 0;
737   for (i=0; i<nrecvs2-1; i++) {
738     starts3[i+1] = starts3[i] + lens2[i];
739   }
740   ierr = PetscMalloc((nt+1)*sizeof(int),&recvs2);CHKERRQ(ierr);
741   ierr = PetscMalloc((nrecvs2+1)*sizeof(MPI_Request),&recv_waits);CHKERRQ(ierr);
742   for (i=0; i<nrecvs2; i++) {
743     ierr = MPI_Irecv(recvs2+starts3[i],lens2[i],MPI_INT,dest[i],tag3,comm,recv_waits+i);CHKERRQ(ierr);
744   }
745 
746   /* send the messages */
747   ierr = PetscMalloc((nsends2+1)*sizeof(MPI_Request),&send_waits);CHKERRQ(ierr);
748   for (i=0; i<nsends2; i++) {
749     ierr = MPI_Isend(sends2+starts2[i],nprocs[i],MPI_INT,source[i],tag3,comm,send_waits+i);CHKERRQ(ierr);
750   }
751 
752   /* wait on receives */
753   ierr = PetscMalloc((nrecvs2+1)*sizeof(MPI_Status),&recv_statuses);CHKERRQ(ierr);
754   ierr = MPI_Waitall(nrecvs2,recv_waits,recv_statuses);CHKERRQ(ierr);
755   ierr = PetscFree(recv_statuses);CHKERRQ(ierr);
756   ierr = PetscFree(recv_waits);CHKERRQ(ierr);
757   ierr = PetscFree(nprocs);CHKERRQ(ierr);
758 
759   if (debug) { /* -----------------------------------  */
760     cnt = 0;
761     for (i=0; i<nrecvs2; i++) {
762       nt = recvs2[cnt++];
763       for (j=0; j<nt; j++) {
764         ierr = PetscSynchronizedPrintf(comm,"[%d] local node %d number of subdomains %d: ",rank,recvs2[cnt],recvs2[cnt+1]);CHKERRQ(ierr);
765         for (k=0; k<recvs2[cnt+1]; k++) {
766           ierr = PetscSynchronizedPrintf(comm,"%d ",recvs2[cnt+2+k]);CHKERRQ(ierr);
767         }
768         cnt += 2 + recvs2[cnt+1];
769         ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
770       }
771     }
772     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
773   } /* -----------------------------------  */
774 
775   /* count number subdomains for each local node */
776   ierr = PetscMalloc(size*sizeof(int),&nprocs);CHKERRQ(ierr);
777   ierr = PetscMemzero(nprocs,size*sizeof(int));CHKERRQ(ierr);
778   cnt  = 0;
779   for (i=0; i<nrecvs2; i++) {
780     nt = recvs2[cnt++];
781     for (j=0; j<nt; j++) {
782       for (k=0; k<recvs2[cnt+1]; k++) {
783         nprocs[recvs2[cnt+2+k]]++;
784       }
785       cnt += 2 + recvs2[cnt+1];
786     }
787   }
788   nt = 0; for (i=0; i<size; i++) nt += (nprocs[i] > 0);
789   *nproc    = nt;
790   ierr = PetscMalloc((nt+1)*sizeof(int),procs);CHKERRQ(ierr);
791   ierr = PetscMalloc((nt+1)*sizeof(int),numprocs);CHKERRQ(ierr);
792   ierr = PetscMalloc((nt+1)*sizeof(int*),indices);CHKERRQ(ierr);
793   ierr = PetscMalloc(size*sizeof(int),&bprocs);CHKERRQ(ierr);
794   cnt       = 0;
795   for (i=0; i<size; i++) {
796     if (nprocs[i] > 0) {
797       bprocs[i]        = cnt;
798       (*procs)[cnt]    = i;
799       (*numprocs)[cnt] = nprocs[i];
800       ierr             = PetscMalloc(nprocs[i]*sizeof(int),&(*indices)[cnt]);CHKERRQ(ierr);
801       cnt++;
802     }
803   }
804 
805   /* make the list of subdomains for each nontrivial local node */
806   ierr = PetscMemzero(*numprocs,nt*sizeof(int));CHKERRQ(ierr);
807   cnt  = 0;
808   for (i=0; i<nrecvs2; i++) {
809     nt = recvs2[cnt++];
810     for (j=0; j<nt; j++) {
811       for (k=0; k<recvs2[cnt+1]; k++) {
812         (*indices)[bprocs[recvs2[cnt+2+k]]][(*numprocs)[bprocs[recvs2[cnt+2+k]]]++] = recvs2[cnt];
813       }
814       cnt += 2 + recvs2[cnt+1];
815     }
816   }
817   ierr = PetscFree(bprocs);CHKERRQ(ierr);
818   ierr = PetscFree(recvs2);CHKERRQ(ierr);
819 
820   /* sort the node indexing by their global numbers */
821   nt = *nproc;
822   for (i=0; i<nt; i++) {
823     ierr = PetscMalloc(((*numprocs)[i])*sizeof(int),&tmp);CHKERRQ(ierr);
824     for (j=0; j<(*numprocs)[i]; j++) {
825       tmp[j] = lindices[(*indices)[i][j]];
826     }
827     ierr = PetscSortIntWithArray((*numprocs)[i],tmp,(*indices)[i]);CHKERRQ(ierr);
828     ierr = PetscFree(tmp);CHKERRQ(ierr);
829   }
830 
831   if (debug) { /* -----------------------------------  */
832     nt = *nproc;
833     for (i=0; i<nt; i++) {
834       ierr = PetscSynchronizedPrintf(comm,"[%d] subdomain %d number of indices %d: ",rank,(*procs)[i],(*numprocs)[i]);CHKERRQ(ierr);
835       for (j=0; j<(*numprocs)[i]; j++) {
836         ierr = PetscSynchronizedPrintf(comm,"%d ",(*indices)[i][j]);CHKERRQ(ierr);
837       }
838       ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
839     }
840     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
841   } /* -----------------------------------  */
842 
843   /* wait on sends */
844   if (nsends2) {
845     ierr = PetscMalloc(nsends2*sizeof(MPI_Status),&send_status);CHKERRQ(ierr);
846     ierr = MPI_Waitall(nsends2,send_waits,send_status);CHKERRQ(ierr);
847     ierr = PetscFree(send_status);CHKERRQ(ierr);
848   }
849 
850   ierr = PetscFree(starts3);CHKERRQ(ierr);
851   ierr = PetscFree(dest);CHKERRQ(ierr);
852   ierr = PetscFree(send_waits);CHKERRQ(ierr);
853 
854   ierr = PetscFree(nownedsenders);CHKERRQ(ierr);
855   ierr = PetscFree(ownedsenders);CHKERRQ(ierr);
856   ierr = PetscFree(starts);CHKERRQ(ierr);
857   ierr = PetscFree(starts2);CHKERRQ(ierr);
858   ierr = PetscFree(lens2);CHKERRQ(ierr);
859 
860   ierr = PetscFree(source);CHKERRQ(ierr);
861   ierr = PetscFree(recvs);CHKERRQ(ierr);
862   ierr = PetscFree(nprocs);CHKERRQ(ierr);
863   ierr = PetscFree(sends2);CHKERRQ(ierr);
864 
865   /* put the information about myself as the first entry in the list */
866   first_procs    = (*procs)[0];
867   first_numprocs = (*numprocs)[0];
868   first_indices  = (*indices)[0];
869   for (i=0; i<*nproc; i++) {
870     if ((*procs)[i] == rank) {
871       (*procs)[0]    = (*procs)[i];
872       (*numprocs)[0] = (*numprocs)[i];
873       (*indices)[0]  = (*indices)[i];
874       (*procs)[i]    = first_procs;
875       (*numprocs)[i] = first_numprocs;
876       (*indices)[i]  = first_indices;
877       break;
878     }
879   }
880 
881   PetscFunctionReturn(0);
882 }
883 
884 #undef __FUNCT__
885 #define __FUNCT__ "ISLocalToGlobalMappingRestoreInfo"
886 /*@C
887     ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by ISLocalToGlobalMappingGetInfo()
888 
889     Collective on ISLocalToGlobalMapping
890 
891     Input Parameters:
892 .   mapping - the mapping from local to global indexing
893 
894     Output Parameter:
895 +   nproc - number of processors that are connected to this one
896 .   proc - neighboring processors
897 .   numproc - number of indices for each processor
898 -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
899 
900     Level: advanced
901 
902 .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate(),
903           ISLocalToGlobalMappingGetInfo()
904 @*/
905 int ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping,int *nproc,int **procs,int **numprocs,int ***indices)
906 {
907   int ierr,i;
908 
909   PetscFunctionBegin;
910   if (*procs) {ierr = PetscFree(*procs);CHKERRQ(ierr);}
911   if (*numprocs) {ierr = PetscFree(*numprocs);CHKERRQ(ierr);}
912   if (*indices) {
913     if ((*indices)[0]) {ierr = PetscFree((*indices)[0]);CHKERRQ(ierr);}
914     for (i=1; i<*nproc; i++) {
915       if ((*indices)[i]) {ierr = PetscFree((*indices)[i]);CHKERRQ(ierr);}
916     }
917     ierr = PetscFree(*indices);CHKERRQ(ierr);
918   }
919   PetscFunctionReturn(0);
920 }
921 
922 
923 
924 
925 
926 
927 
928 
929 
930 
931 
932 
933 
934 
935 
936 
937 
938 
939