1 
2 #include <petsc/private/isimpl.h>    /*I "petscis.h"  I*/
3 #include <petscviewer.h>
4 #include <petscsf.h>
5 
6 const char *const ISColoringTypes[] = {"global","ghosted","ISColoringType","IS_COLORING_",NULL};
7 
ISColoringReference(ISColoring coloring)8 PetscErrorCode ISColoringReference(ISColoring coloring)
9 {
10   PetscFunctionBegin;
11   coloring->refct++;
12   PetscFunctionReturn(0);
13 }
14 
15 /*@C
16 
17     ISColoringSetType - indicates if the coloring is for the local representation (including ghost points) or the global representation
18 
19    Collective on coloring
20 
21    Input Parameters:
22 +    coloring - the coloring object
23 -    type - either IS_COLORING_LOCAL or IS_COLORING_GLOBAL
24 
25    Notes:
26      With IS_COLORING_LOCAL the coloring is in the numbering of the local vector, for IS_COLORING_GLOBAL it is in the number of the global vector
27 
28    Level: intermediate
29 
30 .seealso: MatFDColoringCreate(), ISColoring, ISColoringCreate(), IS_COLORING_LOCAL, IS_COLORING_GLOBAL, ISColoringGetType()
31 
32 @*/
ISColoringSetType(ISColoring coloring,ISColoringType type)33 PetscErrorCode ISColoringSetType(ISColoring coloring,ISColoringType type)
34 {
35   PetscFunctionBegin;
36   coloring->ctype = type;
37   PetscFunctionReturn(0);
38 }
39 
40 /*@C
41 
42     ISColoringGetType - gets if the coloring is for the local representation (including ghost points) or the global representation
43 
44    Collective on coloring
45 
46    Input Parameter:
47 .   coloring - the coloring object
48 
49    Output Parameter:
50 .    type - either IS_COLORING_LOCAL or IS_COLORING_GLOBAL
51 
52    Level: intermediate
53 
54 .seealso: MatFDColoringCreate(), ISColoring, ISColoringCreate(), IS_COLORING_LOCAL, IS_COLORING_GLOBAL, ISColoringSetType()
55 
56 @*/
ISColoringGetType(ISColoring coloring,ISColoringType * type)57 PetscErrorCode ISColoringGetType(ISColoring coloring,ISColoringType *type)
58 {
59   PetscFunctionBegin;
60   *type = coloring->ctype;
61   PetscFunctionReturn(0);
62 }
63 
64 /*@
65    ISColoringDestroy - Destroys a coloring context.
66 
67    Collective on ISColoring
68 
69    Input Parameter:
70 .  iscoloring - the coloring context
71 
72    Level: advanced
73 
74 .seealso: ISColoringView(), MatColoring
75 @*/
ISColoringDestroy(ISColoring * iscoloring)76 PetscErrorCode  ISColoringDestroy(ISColoring *iscoloring)
77 {
78   PetscInt       i;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   if (!*iscoloring) PetscFunctionReturn(0);
83   PetscValidPointer((*iscoloring),1);
84   if (--(*iscoloring)->refct > 0) {*iscoloring = NULL; PetscFunctionReturn(0);}
85 
86   if ((*iscoloring)->is) {
87     for (i=0; i<(*iscoloring)->n; i++) {
88       ierr = ISDestroy(&(*iscoloring)->is[i]);CHKERRQ(ierr);
89     }
90     ierr = PetscFree((*iscoloring)->is);CHKERRQ(ierr);
91   }
92   if ((*iscoloring)->allocated) {ierr = PetscFree((*iscoloring)->colors);CHKERRQ(ierr);}
93   ierr = PetscCommDestroy(&(*iscoloring)->comm);CHKERRQ(ierr);
94   ierr = PetscFree((*iscoloring));CHKERRQ(ierr);
95   PetscFunctionReturn(0);
96 }
97 
98 /*
99   ISColoringViewFromOptions - Processes command line options to determine if/how an ISColoring object is to be viewed.
100 
101   Collective on ISColoring
102 
103   Input Parameters:
104 + obj   - the ISColoring object
105 . prefix - prefix to use for viewing, or NULL to use prefix of 'mat'
106 - optionname - option to activate viewing
107 
108   Level: intermediate
109 
110   Developer Note: This cannot use PetscObjectViewFromOptions() because ISColoring is not a PetscObject
111 
112 */
ISColoringViewFromOptions(ISColoring obj,PetscObject bobj,const char optionname[])113 PetscErrorCode ISColoringViewFromOptions(ISColoring obj,PetscObject bobj,const char optionname[])
114 {
115   PetscErrorCode    ierr;
116   PetscViewer       viewer;
117   PetscBool         flg;
118   PetscViewerFormat format;
119   char              *prefix;
120 
121   PetscFunctionBegin;
122   prefix = bobj ? bobj->prefix : NULL;
123   ierr   = PetscOptionsGetViewer(obj->comm,NULL,prefix,optionname,&viewer,&format,&flg);CHKERRQ(ierr);
124   if (flg) {
125     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
126     ierr = ISColoringView(obj,viewer);CHKERRQ(ierr);
127     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
128     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
129   }
130   PetscFunctionReturn(0);
131 }
132 
133 /*@C
134    ISColoringView - Views a coloring context.
135 
136    Collective on ISColoring
137 
138    Input Parameters:
139 +  iscoloring - the coloring context
140 -  viewer - the viewer
141 
142    Level: advanced
143 
144 .seealso: ISColoringDestroy(), ISColoringGetIS(), MatColoring
145 @*/
ISColoringView(ISColoring iscoloring,PetscViewer viewer)146 PetscErrorCode  ISColoringView(ISColoring iscoloring,PetscViewer viewer)
147 {
148   PetscInt       i;
149   PetscErrorCode ierr;
150   PetscBool      iascii;
151   IS             *is;
152 
153   PetscFunctionBegin;
154   PetscValidPointer(iscoloring,1);
155   if (!viewer) {
156     ierr = PetscViewerASCIIGetStdout(iscoloring->comm,&viewer);CHKERRQ(ierr);
157   }
158   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
159 
160   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
161   if (iascii) {
162     MPI_Comm    comm;
163     PetscMPIInt size,rank;
164 
165     ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
166     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
167     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
168     ierr = PetscViewerASCIIPrintf(viewer,"ISColoring Object: %d MPI processes\n",size);CHKERRQ(ierr);
169     ierr = PetscViewerASCIIPrintf(viewer,"ISColoringType: %s\n",ISColoringTypes[iscoloring->ctype]);CHKERRQ(ierr);
170     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
171     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of colors %d\n",rank,iscoloring->n);CHKERRQ(ierr);
172     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
173     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
174   }
175 
176   ierr = ISColoringGetIS(iscoloring,PETSC_USE_POINTER,PETSC_IGNORE,&is);CHKERRQ(ierr);
177   for (i=0; i<iscoloring->n; i++) {
178     ierr = ISView(iscoloring->is[i],viewer);CHKERRQ(ierr);
179   }
180   ierr = ISColoringRestoreIS(iscoloring,PETSC_USE_POINTER,&is);CHKERRQ(ierr);
181   PetscFunctionReturn(0);
182 }
183 
184 /*@C
185    ISColoringGetColors - Returns an array with the color for each node
186 
187    Not Collective
188 
189    Input Parameter:
190 .  iscoloring - the coloring context
191 
192    Output Parameters:
193 +  n - number of nodes
194 .  nc - number of colors
195 -  colors - color for each node
196 
197    Level: advanced
198 
199 .seealso: ISColoringRestoreIS(), ISColoringView(), ISColoringGetIS()
200 @*/
ISColoringGetColors(ISColoring iscoloring,PetscInt * n,PetscInt * nc,const ISColoringValue ** colors)201 PetscErrorCode  ISColoringGetColors(ISColoring iscoloring,PetscInt *n,PetscInt *nc,const ISColoringValue **colors)
202 {
203   PetscFunctionBegin;
204   PetscValidPointer(iscoloring,1);
205 
206   if (n) *n = iscoloring->N;
207   if (nc) *nc = iscoloring->n;
208   if (colors) *colors = iscoloring->colors;
209   PetscFunctionReturn(0);
210 }
211 
212 /*@C
213    ISColoringGetIS - Extracts index sets from the coloring context. Each is contains the nodes of one color
214 
215    Collective on ISColoring
216 
217    Input Parameter:
218 +  iscoloring - the coloring context
219 -  mode - if this value is PETSC_OWN_POINTER then the caller owns the pointer and must free the array of IS and each IS in the array
220 
221    Output Parameters:
222 +  nn - number of index sets in the coloring context
223 -  is - array of index sets
224 
225    Level: advanced
226 
227 .seealso: ISColoringRestoreIS(), ISColoringView(), ISColoringGetColoring()
228 @*/
ISColoringGetIS(ISColoring iscoloring,PetscCopyMode mode,PetscInt * nn,IS * isis[])229 PetscErrorCode  ISColoringGetIS(ISColoring iscoloring,PetscCopyMode mode, PetscInt *nn,IS *isis[])
230 {
231   PetscErrorCode ierr;
232 
233   PetscFunctionBegin;
234   PetscValidPointer(iscoloring,1);
235 
236   if (nn) *nn = iscoloring->n;
237   if (isis) {
238     if (!iscoloring->is) {
239       PetscInt        *mcolors,**ii,nc = iscoloring->n,i,base, n = iscoloring->N;
240       ISColoringValue *colors = iscoloring->colors;
241       IS              *is;
242 
243       if (PetscDefined(USE_DEBUG)) {
244         for (i=0; i<n; i++) {
245           if (((PetscInt)colors[i]) >= nc) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coloring is our of range index %d value %d number colors %d",(int)i,(int)colors[i],(int)nc);
246         }
247       }
248 
249       /* generate the lists of nodes for each color */
250       ierr = PetscCalloc1(nc,&mcolors);CHKERRQ(ierr);
251       for (i=0; i<n; i++) mcolors[colors[i]]++;
252 
253       ierr = PetscMalloc1(nc,&ii);CHKERRQ(ierr);
254       ierr = PetscMalloc1(n,&ii[0]);CHKERRQ(ierr);
255       for (i=1; i<nc; i++) ii[i] = ii[i-1] + mcolors[i-1];
256       ierr = PetscArrayzero(mcolors,nc);CHKERRQ(ierr);
257 
258       if (iscoloring->ctype == IS_COLORING_GLOBAL) {
259         ierr = MPI_Scan(&iscoloring->N,&base,1,MPIU_INT,MPI_SUM,iscoloring->comm);CHKERRQ(ierr);
260         base -= iscoloring->N;
261         for (i=0; i<n; i++) ii[colors[i]][mcolors[colors[i]]++] = i + base; /* global idx */
262       } else if (iscoloring->ctype == IS_COLORING_LOCAL) {
263         for (i=0; i<n; i++) ii[colors[i]][mcolors[colors[i]]++] = i;   /* local idx */
264       } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not provided for this ISColoringType type");
265 
266       ierr = PetscMalloc1(nc,&is);CHKERRQ(ierr);
267       for (i=0; i<nc; i++) {
268         ierr = ISCreateGeneral(iscoloring->comm,mcolors[i],ii[i],PETSC_COPY_VALUES,is+i);CHKERRQ(ierr);
269       }
270 
271       if (mode != PETSC_OWN_POINTER) iscoloring->is = is;
272       *isis = is;
273       ierr = PetscFree(ii[0]);CHKERRQ(ierr);
274       ierr = PetscFree(ii);CHKERRQ(ierr);
275       ierr = PetscFree(mcolors);CHKERRQ(ierr);
276     } else {
277       *isis = iscoloring->is;
278     }
279   }
280   PetscFunctionReturn(0);
281 }
282 
283 /*@C
284    ISColoringRestoreIS - Restores the index sets extracted from the coloring context
285 
286    Collective on ISColoring
287 
288    Input Parameter:
289 +  iscoloring - the coloring context
290 .  mode - who retains ownership of the is
291 -  is - array of index sets
292 
293    Level: advanced
294 
295 .seealso: ISColoringGetIS(), ISColoringView()
296 @*/
ISColoringRestoreIS(ISColoring iscoloring,PetscCopyMode mode,IS * is[])297 PetscErrorCode  ISColoringRestoreIS(ISColoring iscoloring,PetscCopyMode mode,IS *is[])
298 {
299   PetscFunctionBegin;
300   PetscValidPointer(iscoloring,1);
301 
302   /* currently nothing is done here */
303   PetscFunctionReturn(0);
304 }
305 
306 
307 /*@
308     ISColoringCreate - Generates an ISColoring context from lists (provided
309     by each processor) of colors for each node.
310 
311     Collective
312 
313     Input Parameters:
314 +   comm - communicator for the processors creating the coloring
315 .   ncolors - max color value
316 .   n - number of nodes on this processor
317 .   colors - array containing the colors for this processor, color numbers begin at 0.
318 -   mode - see PetscCopyMode for meaning of this flag.
319 
320     Output Parameter:
321 .   iscoloring - the resulting coloring data structure
322 
323     Options Database Key:
324 .   -is_coloring_view - Activates ISColoringView()
325 
326    Level: advanced
327 
328     Notes:
329     By default sets coloring type to  IS_COLORING_GLOBAL
330 
331 .seealso: MatColoringCreate(), ISColoringView(), ISColoringDestroy(), ISColoringSetType()
332 
333 @*/
ISColoringCreate(MPI_Comm comm,PetscInt ncolors,PetscInt n,const ISColoringValue colors[],PetscCopyMode mode,ISColoring * iscoloring)334 PetscErrorCode  ISColoringCreate(MPI_Comm comm,PetscInt ncolors,PetscInt n,const ISColoringValue colors[],PetscCopyMode mode,ISColoring *iscoloring)
335 {
336   PetscErrorCode ierr;
337   PetscMPIInt    size,rank,tag;
338   PetscInt       base,top,i;
339   PetscInt       nc,ncwork;
340   MPI_Status     status;
341 
342   PetscFunctionBegin;
343   if (ncolors != PETSC_DECIDE && ncolors > IS_COLORING_MAX) {
344     if (ncolors > PETSC_MAX_UINT16) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Max color value exceeds %d limit. This number is unrealistic. Perhaps a bug in code?\nCurrent max: %d user requested: %D",PETSC_MAX_UINT16,PETSC_IS_COLORING_MAX,ncolors);
345     else                 SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Max color value exceeds limit. Perhaps reconfigure PETSc with --with-is-color-value-type=short?\n Current max: %d user requested: %D",PETSC_IS_COLORING_MAX,ncolors);
346   }
347   ierr = PetscNew(iscoloring);CHKERRQ(ierr);
348   ierr = PetscCommDuplicate(comm,&(*iscoloring)->comm,&tag);CHKERRQ(ierr);
349   comm = (*iscoloring)->comm;
350 
351   /* compute the number of the first node on my processor */
352   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
353 
354   /* should use MPI_Scan() */
355   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
356   if (!rank) {
357     base = 0;
358     top  = n;
359   } else {
360     ierr = MPI_Recv(&base,1,MPIU_INT,rank-1,tag,comm,&status);CHKERRQ(ierr);
361     top  = base+n;
362   }
363   if (rank < size-1) {
364     ierr = MPI_Send(&top,1,MPIU_INT,rank+1,tag,comm);CHKERRQ(ierr);
365   }
366 
367   /* compute the total number of colors */
368   ncwork = 0;
369   for (i=0; i<n; i++) {
370     if (ncwork < colors[i]) ncwork = colors[i];
371   }
372   ncwork++;
373   ierr = MPIU_Allreduce(&ncwork,&nc,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
374   if (nc > ncolors) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of colors passed in %D is less then the actual number of colors in array %D",ncolors,nc);
375   (*iscoloring)->n      = nc;
376   (*iscoloring)->is     = NULL;
377   (*iscoloring)->N      = n;
378   (*iscoloring)->refct  = 1;
379   (*iscoloring)->ctype  = IS_COLORING_GLOBAL;
380   if (mode == PETSC_COPY_VALUES) {
381     ierr = PetscMalloc1(n,&(*iscoloring)->colors);CHKERRQ(ierr);
382     ierr = PetscLogObjectMemory((PetscObject)(*iscoloring),n*sizeof(ISColoringValue));CHKERRQ(ierr);
383     ierr = PetscArraycpy((*iscoloring)->colors,colors,n);CHKERRQ(ierr);
384     (*iscoloring)->allocated = PETSC_TRUE;
385   } else if (mode == PETSC_OWN_POINTER) {
386     (*iscoloring)->colors    = (ISColoringValue*)colors;
387     (*iscoloring)->allocated = PETSC_TRUE;
388   } else {
389     (*iscoloring)->colors    = (ISColoringValue*)colors;
390     (*iscoloring)->allocated = PETSC_FALSE;
391   }
392   ierr = ISColoringViewFromOptions(*iscoloring,NULL,"-is_coloring_view");CHKERRQ(ierr);
393   ierr = PetscInfo1(0,"Number of colors %D\n",nc);CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 /*@
398     ISBuildTwoSided - Takes an IS that describes where we will go. Generates an IS that contains new numbers from remote or local
399     on the IS.
400 
401     Collective on IS
402 
403     Input Parameters:
404 +   ito - an IS describes where we will go. Negative target rank will be ignored
405 -   toindx - an IS describes what indices should send. NULL means sending natural numbering
406 
407     Output Parameter:
408 .   rows - contains new numbers from remote or local
409 
410    Level: advanced
411 
412 .seealso: MatPartitioningCreate(), ISPartitioningToNumbering(), ISPartitioningCount()
413 
414 @*/
ISBuildTwoSided(IS ito,IS toindx,IS * rows)415 PetscErrorCode  ISBuildTwoSided(IS ito,IS toindx, IS *rows)
416 {
417    const PetscInt *ito_indices,*toindx_indices;
418    PetscInt       *send_indices,rstart,*recv_indices,nrecvs,nsends;
419    PetscInt       *tosizes,*fromsizes,i,j,*tosizes_tmp,*tooffsets_tmp,ito_ln;
420    PetscMPIInt    *toranks,*fromranks,size,target_rank,*fromperm_newtoold,nto,nfrom;
421    PetscLayout     isrmap;
422    MPI_Comm        comm;
423    PetscSF         sf;
424    PetscSFNode    *iremote;
425    PetscErrorCode  ierr;
426 
427    PetscFunctionBegin;
428    ierr = PetscObjectGetComm((PetscObject)ito,&comm);CHKERRQ(ierr);
429    ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
430    ierr = ISGetLocalSize(ito,&ito_ln);CHKERRQ(ierr);
431    /* why we do not have ISGetLayout? */
432    isrmap = ito->map;
433    ierr = PetscLayoutGetRange(isrmap,&rstart,NULL);CHKERRQ(ierr);
434    ierr = ISGetIndices(ito,&ito_indices);CHKERRQ(ierr);
435    ierr = PetscCalloc2(size,&tosizes_tmp,size+1,&tooffsets_tmp);CHKERRQ(ierr);
436    for (i=0; i<ito_ln; i++) {
437      if (ito_indices[i]<0) continue;
438      if (ito_indices[i]>=size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"target rank %d is larger than communicator size %d ",ito_indices[i],size);
439      tosizes_tmp[ito_indices[i]]++;
440    }
441    nto = 0;
442    for (i=0; i<size; i++) {
443      tooffsets_tmp[i+1] = tooffsets_tmp[i]+tosizes_tmp[i];
444      if (tosizes_tmp[i]>0) nto++;
445    }
446    ierr = PetscCalloc2(nto,&toranks,2*nto,&tosizes);CHKERRQ(ierr);
447    nto  = 0;
448    for (i=0; i<size; i++) {
449      if (tosizes_tmp[i]>0) {
450        toranks[nto]     = i;
451        tosizes[2*nto]   = tosizes_tmp[i];/* size */
452        tosizes[2*nto+1] = tooffsets_tmp[i];/* offset */
453        nto++;
454      }
455    }
456    nsends = tooffsets_tmp[size];
457    ierr   = PetscCalloc1(nsends,&send_indices);CHKERRQ(ierr);
458    if (toindx) {
459      ierr = ISGetIndices(toindx,&toindx_indices);CHKERRQ(ierr);
460    }
461    for (i=0; i<ito_ln; i++) {
462      if (ito_indices[i]<0) continue;
463      target_rank = ito_indices[i];
464      send_indices[tooffsets_tmp[target_rank]] = toindx? toindx_indices[i]:(i+rstart);
465      tooffsets_tmp[target_rank]++;
466    }
467    if (toindx) {
468      ierr = ISRestoreIndices(toindx,&toindx_indices);CHKERRQ(ierr);
469    }
470    ierr = ISRestoreIndices(ito,&ito_indices);CHKERRQ(ierr);
471    ierr = PetscFree2(tosizes_tmp,tooffsets_tmp);CHKERRQ(ierr);
472    ierr = PetscCommBuildTwoSided(comm,2,MPIU_INT,nto,toranks,tosizes,&nfrom,&fromranks,&fromsizes);CHKERRQ(ierr);
473    ierr = PetscFree2(toranks,tosizes);CHKERRQ(ierr);
474    ierr = PetscMalloc1(nfrom,&fromperm_newtoold);CHKERRQ(ierr);
475    for (i=0; i<nfrom; i++) fromperm_newtoold[i] = i;
476    ierr   = PetscSortMPIIntWithArray(nfrom,fromranks,fromperm_newtoold);CHKERRQ(ierr);
477    nrecvs = 0;
478    for (i=0; i<nfrom; i++) nrecvs += fromsizes[i*2];
479    ierr   = PetscCalloc1(nrecvs,&recv_indices);CHKERRQ(ierr);
480    ierr   = PetscMalloc1(nrecvs,&iremote);CHKERRQ(ierr);
481    nrecvs = 0;
482    for (i=0; i<nfrom; i++) {
483      for (j=0; j<fromsizes[2*fromperm_newtoold[i]]; j++) {
484        iremote[nrecvs].rank    = fromranks[i];
485        iremote[nrecvs++].index = fromsizes[2*fromperm_newtoold[i]+1]+j;
486      }
487    }
488    ierr = PetscSFCreate(comm,&sf);CHKERRQ(ierr);
489    ierr = PetscSFSetGraph(sf,nsends,nrecvs,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
490    ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr);
491    /* how to put a prefix ? */
492    ierr = PetscSFSetFromOptions(sf);CHKERRQ(ierr);
493    ierr = PetscSFBcastBegin(sf,MPIU_INT,send_indices,recv_indices);CHKERRQ(ierr);
494    ierr = PetscSFBcastEnd(sf,MPIU_INT,send_indices,recv_indices);CHKERRQ(ierr);
495    ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
496    ierr = PetscFree(fromranks);CHKERRQ(ierr);
497    ierr = PetscFree(fromsizes);CHKERRQ(ierr);
498    ierr = PetscFree(fromperm_newtoold);CHKERRQ(ierr);
499    ierr = PetscFree(send_indices);CHKERRQ(ierr);
500    if (rows) {
501      ierr = PetscSortInt(nrecvs,recv_indices);CHKERRQ(ierr);
502      ierr = ISCreateGeneral(comm,nrecvs,recv_indices,PETSC_OWN_POINTER,rows);CHKERRQ(ierr);
503    } else {
504      ierr = PetscFree(recv_indices);CHKERRQ(ierr);
505    }
506    PetscFunctionReturn(0);
507 }
508 
509 
510 /*@
511     ISPartitioningToNumbering - Takes an ISPartitioning and on each processor
512     generates an IS that contains a new global node number for each index based
513     on the partitioing.
514 
515     Collective on IS
516 
517     Input Parameters:
518 .   partitioning - a partitioning as generated by MatPartitioningApply()
519                    or MatPartitioningApplyND()
520 
521     Output Parameter:
522 .   is - on each processor the index set that defines the global numbers
523          (in the new numbering) for all the nodes currently (before the partitioning)
524          on that processor
525 
526    Level: advanced
527 
528 .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningCount()
529 
530 @*/
ISPartitioningToNumbering(IS part,IS * is)531 PetscErrorCode  ISPartitioningToNumbering(IS part,IS *is)
532 {
533   MPI_Comm       comm;
534   IS             ndorder;
535   PetscInt       i,np,npt,n,*starts = NULL,*sums = NULL,*lsizes = NULL,*newi = NULL;
536   const PetscInt *indices = NULL;
537   PetscErrorCode ierr;
538 
539   PetscFunctionBegin;
540   PetscValidHeaderSpecific(part,IS_CLASSID,1);
541   PetscValidPointer(is,2);
542   /* see if the partitioning comes from nested dissection */
543   ierr = PetscObjectQuery((PetscObject)part,"_petsc_matpartitioning_ndorder",(PetscObject*)&ndorder);CHKERRQ(ierr);
544   if (ndorder) {
545     ierr = PetscObjectReference((PetscObject)ndorder);CHKERRQ(ierr);
546     *is  = ndorder;
547     PetscFunctionReturn(0);
548   }
549 
550   ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
551   /* count the number of partitions, i.e., virtual processors */
552   ierr = ISGetLocalSize(part,&n);CHKERRQ(ierr);
553   ierr = ISGetIndices(part,&indices);CHKERRQ(ierr);
554   np   = 0;
555   for (i=0; i<n; i++) np = PetscMax(np,indices[i]);
556   ierr = MPIU_Allreduce(&np,&npt,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
557   np   = npt+1; /* so that it looks like a MPI_Comm_size output */
558 
559   /*
560         lsizes - number of elements of each partition on this particular processor
561         sums - total number of "previous" nodes for any particular partition
562         starts - global number of first element in each partition on this processor
563   */
564   ierr = PetscMalloc3(np,&lsizes,np,&starts,np,&sums);CHKERRQ(ierr);
565   ierr = PetscArrayzero(lsizes,np);CHKERRQ(ierr);
566   for (i=0; i<n; i++) lsizes[indices[i]]++;
567   ierr = MPIU_Allreduce(lsizes,sums,np,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr);
568   ierr = MPI_Scan(lsizes,starts,np,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr);
569   for (i=0; i<np; i++) starts[i] -= lsizes[i];
570   for (i=1; i<np; i++) {
571     sums[i]   += sums[i-1];
572     starts[i] += sums[i-1];
573   }
574 
575   /*
576       For each local index give it the new global number
577   */
578   ierr = PetscMalloc1(n,&newi);CHKERRQ(ierr);
579   for (i=0; i<n; i++) newi[i] = starts[indices[i]]++;
580   ierr = PetscFree3(lsizes,starts,sums);CHKERRQ(ierr);
581 
582   ierr = ISRestoreIndices(part,&indices);CHKERRQ(ierr);
583   ierr = ISCreateGeneral(comm,n,newi,PETSC_OWN_POINTER,is);CHKERRQ(ierr);
584   ierr = ISSetPermutation(*is);CHKERRQ(ierr);
585   PetscFunctionReturn(0);
586 }
587 
588 /*@
589     ISPartitioningCount - Takes a ISPartitioning and determines the number of
590     resulting elements on each (partition) process
591 
592     Collective on IS
593 
594     Input Parameters:
595 +   partitioning - a partitioning as generated by MatPartitioningApply() or
596                    MatPartitioningApplyND()
597 -   len - length of the array count, this is the total number of partitions
598 
599     Output Parameter:
600 .   count - array of length size, to contain the number of elements assigned
601         to each partition, where size is the number of partitions generated
602          (see notes below).
603 
604    Level: advanced
605 
606     Notes:
607         By default the number of partitions generated (and thus the length
608         of count) is the size of the communicator associated with IS,
609         but it can be set by MatPartitioningSetNParts. The resulting array
610         of lengths can for instance serve as input of PCBJacobiSetTotalBlocks.
611         If the partitioning has been obtained by MatPartitioningApplyND(),
612         the returned count does not include the separators.
613 
614 .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningToNumbering(),
615         MatPartitioningSetNParts(), MatPartitioningApply(), MatPartitioningApplyND()
616 
617 @*/
ISPartitioningCount(IS part,PetscInt len,PetscInt count[])618 PetscErrorCode  ISPartitioningCount(IS part,PetscInt len,PetscInt count[])
619 {
620   MPI_Comm       comm;
621   PetscInt       i,n,*lsizes;
622   const PetscInt *indices;
623   PetscErrorCode ierr;
624   PetscMPIInt    npp;
625 
626   PetscFunctionBegin;
627   ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
628   if (len == PETSC_DEFAULT) {
629     PetscMPIInt size;
630     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
631     len  = (PetscInt) size;
632   }
633 
634   /* count the number of partitions */
635   ierr = ISGetLocalSize(part,&n);CHKERRQ(ierr);
636   ierr = ISGetIndices(part,&indices);CHKERRQ(ierr);
637   if (PetscDefined(USE_DEBUG)) {
638     PetscInt np = 0,npt;
639     for (i=0; i<n; i++) np = PetscMax(np,indices[i]);
640     ierr = MPIU_Allreduce(&np,&npt,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
641     np   = npt+1; /* so that it looks like a MPI_Comm_size output */
642     if (np > len) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Length of count array %D is less than number of partitions %D",len,np);
643   }
644 
645   /*
646         lsizes - number of elements of each partition on this particular processor
647         sums - total number of "previous" nodes for any particular partition
648         starts - global number of first element in each partition on this processor
649   */
650   ierr = PetscCalloc1(len,&lsizes);CHKERRQ(ierr);
651   for (i=0; i<n; i++) {
652     if (indices[i] > -1) lsizes[indices[i]]++;
653   }
654   ierr = ISRestoreIndices(part,&indices);CHKERRQ(ierr);
655   ierr = PetscMPIIntCast(len,&npp);CHKERRQ(ierr);
656   ierr = MPIU_Allreduce(lsizes,count,npp,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr);
657   ierr = PetscFree(lsizes);CHKERRQ(ierr);
658   PetscFunctionReturn(0);
659 }
660 
661 /*@
662     ISAllGather - Given an index set (IS) on each processor, generates a large
663     index set (same on each processor) by concatenating together each
664     processors index set.
665 
666     Collective on IS
667 
668     Input Parameter:
669 .   is - the distributed index set
670 
671     Output Parameter:
672 .   isout - the concatenated index set (same on all processors)
673 
674     Notes:
675     ISAllGather() is clearly not scalable for large index sets.
676 
677     The IS created on each processor must be created with a common
678     communicator (e.g., PETSC_COMM_WORLD). If the index sets were created
679     with PETSC_COMM_SELF, this routine will not work as expected, since
680     each process will generate its own new IS that consists only of
681     itself.
682 
683     The communicator for this new IS is PETSC_COMM_SELF
684 
685     Level: intermediate
686 
687 .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock()
688 @*/
ISAllGather(IS is,IS * isout)689 PetscErrorCode  ISAllGather(IS is,IS *isout)
690 {
691   PetscErrorCode ierr;
692   PetscInt       *indices,n,i,N,step,first;
693   const PetscInt *lindices;
694   MPI_Comm       comm;
695   PetscMPIInt    size,*sizes = NULL,*offsets = NULL,nn;
696   PetscBool      stride;
697 
698   PetscFunctionBegin;
699   PetscValidHeaderSpecific(is,IS_CLASSID,1);
700   PetscValidPointer(isout,2);
701 
702   ierr = PetscObjectGetComm((PetscObject)is,&comm);CHKERRQ(ierr);
703   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
704   ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
705   ierr = PetscObjectTypeCompare((PetscObject)is,ISSTRIDE,&stride);CHKERRQ(ierr);
706   if (size == 1 && stride) { /* should handle parallel ISStride also */
707     ierr = ISStrideGetInfo(is,&first,&step);CHKERRQ(ierr);
708     ierr = ISCreateStride(PETSC_COMM_SELF,n,first,step,isout);CHKERRQ(ierr);
709   } else {
710     ierr = PetscMalloc2(size,&sizes,size,&offsets);CHKERRQ(ierr);
711 
712     ierr       = PetscMPIIntCast(n,&nn);CHKERRQ(ierr);
713     ierr       = MPI_Allgather(&nn,1,MPI_INT,sizes,1,MPI_INT,comm);CHKERRQ(ierr);
714     offsets[0] = 0;
715     for (i=1; i<size; i++) {
716       PetscInt s = offsets[i-1] + sizes[i-1];
717       ierr = PetscMPIIntCast(s,&offsets[i]);CHKERRQ(ierr);
718     }
719     N = offsets[size-1] + sizes[size-1];
720 
721     ierr = PetscMalloc1(N,&indices);CHKERRQ(ierr);
722     ierr = ISGetIndices(is,&lindices);CHKERRQ(ierr);
723     ierr = MPI_Allgatherv((void*)lindices,nn,MPIU_INT,indices,sizes,offsets,MPIU_INT,comm);CHKERRQ(ierr);
724     ierr = ISRestoreIndices(is,&lindices);CHKERRQ(ierr);
725     ierr = PetscFree2(sizes,offsets);CHKERRQ(ierr);
726 
727     ierr = ISCreateGeneral(PETSC_COMM_SELF,N,indices,PETSC_OWN_POINTER,isout);CHKERRQ(ierr);
728   }
729   PetscFunctionReturn(0);
730 }
731 
732 /*@C
733     ISAllGatherColors - Given a a set of colors on each processor, generates a large
734     set (same on each processor) by concatenating together each processors colors
735 
736     Collective
737 
738     Input Parameter:
739 +   comm - communicator to share the indices
740 .   n - local size of set
741 -   lindices - local colors
742 
743     Output Parameter:
744 +   outN - total number of indices
745 -   outindices - all of the colors
746 
747     Notes:
748     ISAllGatherColors() is clearly not scalable for large index sets.
749 
750 
751     Level: intermediate
752 
753 .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather()
754 @*/
ISAllGatherColors(MPI_Comm comm,PetscInt n,ISColoringValue * lindices,PetscInt * outN,ISColoringValue * outindices[])755 PetscErrorCode  ISAllGatherColors(MPI_Comm comm,PetscInt n,ISColoringValue *lindices,PetscInt *outN,ISColoringValue *outindices[])
756 {
757   ISColoringValue *indices;
758   PetscErrorCode  ierr;
759   PetscInt        i,N;
760   PetscMPIInt     size,*offsets = NULL,*sizes = NULL, nn = n;
761 
762   PetscFunctionBegin;
763   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
764   ierr = PetscMalloc2(size,&sizes,size,&offsets);CHKERRQ(ierr);
765 
766   ierr       = MPI_Allgather(&nn,1,MPI_INT,sizes,1,MPI_INT,comm);CHKERRQ(ierr);
767   offsets[0] = 0;
768   for (i=1; i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
769   N    = offsets[size-1] + sizes[size-1];
770   ierr = PetscFree2(sizes,offsets);CHKERRQ(ierr);
771 
772   ierr = PetscMalloc1(N+1,&indices);CHKERRQ(ierr);
773   ierr = MPI_Allgatherv(lindices,(PetscMPIInt)n,MPIU_COLORING_VALUE,indices,sizes,offsets,MPIU_COLORING_VALUE,comm);CHKERRQ(ierr);
774 
775   *outindices = indices;
776   if (outN) *outN = N;
777   PetscFunctionReturn(0);
778 }
779 
780 /*@
781     ISComplement - Given an index set (IS) generates the complement index set. That is all
782        all indices that are NOT in the given set.
783 
784     Collective on IS
785 
786     Input Parameter:
787 +   is - the index set
788 .   nmin - the first index desired in the local part of the complement
789 -   nmax - the largest index desired in the local part of the complement (note that all indices in is must be greater or equal to nmin and less than nmax)
790 
791     Output Parameter:
792 .   isout - the complement
793 
794     Notes:
795     The communicator for this new IS is the same as for the input IS
796 
797       For a parallel IS, this will generate the local part of the complement on each process
798 
799       To generate the entire complement (on each process) of a parallel IS, first call ISAllGather() and then
800     call this routine.
801 
802     Level: intermediate
803 
804 .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather()
805 @*/
ISComplement(IS is,PetscInt nmin,PetscInt nmax,IS * isout)806 PetscErrorCode  ISComplement(IS is,PetscInt nmin,PetscInt nmax,IS *isout)
807 {
808   PetscErrorCode ierr;
809   const PetscInt *indices;
810   PetscInt       n,i,j,unique,cnt,*nindices;
811   PetscBool      sorted;
812 
813   PetscFunctionBegin;
814   PetscValidHeaderSpecific(is,IS_CLASSID,1);
815   PetscValidPointer(isout,3);
816   if (nmin < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nmin %D cannot be negative",nmin);
817   if (nmin > nmax) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nmin %D cannot be greater than nmax %D",nmin,nmax);
818   ierr = ISSorted(is,&sorted);CHKERRQ(ierr);
819   if (!sorted) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Index set must be sorted");
820 
821   ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
822   ierr = ISGetIndices(is,&indices);CHKERRQ(ierr);
823   if (PetscDefined(USE_DEBUG)) {
824     for (i=0; i<n; i++) {
825       if (indices[i] <  nmin) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D's value %D is smaller than minimum given %D",i,indices[i],nmin);
826       if (indices[i] >= nmax) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D's value %D is larger than maximum given %D",i,indices[i],nmax);
827     }
828   }
829   /* Count number of unique entries */
830   unique = (n>0);
831   for (i=0; i<n-1; i++) {
832     if (indices[i+1] != indices[i]) unique++;
833   }
834   ierr = PetscMalloc1(nmax-nmin-unique,&nindices);CHKERRQ(ierr);
835   cnt  = 0;
836   for (i=nmin,j=0; i<nmax; i++) {
837     if (j<n && i==indices[j]) do { j++; } while (j<n && i==indices[j]);
838     else nindices[cnt++] = i;
839   }
840   if (cnt != nmax-nmin-unique) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Number of entries found in complement %D does not match expected %D",cnt,nmax-nmin-unique);
841   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),cnt,nindices,PETSC_OWN_POINTER,isout);CHKERRQ(ierr);
842   ierr = ISRestoreIndices(is,&indices);CHKERRQ(ierr);
843   PetscFunctionReturn(0);
844 }
845