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