Actual source code: iscoloring.c
1: /*$Id: iscoloring.c,v 1.70 2001/06/21 21:15:55 bsmith Exp $*/
3: #include petscsys.h
4: #include petscis.h
8: /*@C
9: ISColoringDestroy - Destroys a coloring context.
11: Collective on ISColoring
13: Input Parameter:
14: . iscoloring - the coloring context
16: Level: advanced
18: .seealso: ISColoringView(), MatGetColoring()
19: @*/
20: int ISColoringDestroy(ISColoring iscoloring)
21: {
22: int i,ierr;
26: if (--iscoloring->refct > 0) return(0);
28: if (iscoloring->is) {
29: for (i=0; i<iscoloring->n; i++) {
30: ISDestroy(iscoloring->is[i]);
31: }
32: PetscFree(iscoloring->is);
33: }
34: if (iscoloring->colors) {
35: PetscFree(iscoloring->colors);
36: }
37: PetscCommDestroy(&iscoloring->comm);
38: PetscFree(iscoloring);
39: return(0);
40: }
44: /*@C
45: ISColoringView - Views a coloring context.
47: Collective on ISColoring
49: Input Parameters:
50: + iscoloring - the coloring context
51: - viewer - the viewer
53: Level: advanced
55: .seealso: ISColoringDestroy(), ISColoringGetIS(), MatGetColoring()
56: @*/
57: int ISColoringView(ISColoring iscoloring,PetscViewer viewer)
58: {
59: int i,ierr;
60: PetscTruth isascii;
61: IS *is;
65: if (!viewer) viewer = PETSC_VIEWER_STDOUT_(iscoloring->comm);
68: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
69: if (isascii) {
70: MPI_Comm comm;
71: int rank;
72: PetscObjectGetComm((PetscObject)viewer,&comm);
73: MPI_Comm_rank(comm,&rank);
74: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of colors %d\n",rank,iscoloring->n);
75: PetscViewerFlush(viewer);
76: } else {
77: SETERRQ1(1,"Viewer type %s not supported for ISColoring",((PetscObject)viewer)->type_name);
78: }
80: ISColoringGetIS(iscoloring,PETSC_IGNORE,&is);
81: for (i=0; i<iscoloring->n; i++) {
82: ISView(iscoloring->is[i],viewer);
83: }
84: ISColoringRestoreIS(iscoloring,&is);
85: return(0);
86: }
90: /*@C
91: ISColoringGetIS - Extracts index sets from the coloring context
93: Collective on ISColoring
95: Input Parameter:
96: . iscoloring - the coloring context
98: Output Parameters:
99: + nn - number of index sets in the coloring context
100: - is - array of index sets
102: Level: advanced
104: .seealso: ISColoringRestoreIS(), ISColoringView()
105: @*/
106: int ISColoringGetIS(ISColoring iscoloring,int *nn,IS *isis[])
107: {
113: if (nn) *nn = iscoloring->n;
114: if (isis) {
115: if (!iscoloring->is) {
116: int *mcolors,**ii,nc = iscoloring->n,i,base, n = iscoloring->N;
117: ISColoringValue *colors = iscoloring->colors;
118: IS *is;
119:
120: /* generate the lists of nodes for each color */
121: PetscMalloc((nc+1)*sizeof(int),&mcolors);
122: PetscMemzero(mcolors,nc*sizeof(int));
123: for (i=0; i<n; i++) {
124: mcolors[colors[i]]++;
125: }
127: PetscMalloc((nc+1)*sizeof(int*),&ii);
128: PetscMalloc((n+1)*sizeof(int),&ii[0]);
129: for (i=1; i<nc; i++) {
130: ii[i] = ii[i-1] + mcolors[i-1];
131: }
132:
133: MPI_Scan(&iscoloring->N,&base,1,MPI_INT,MPI_SUM,iscoloring->comm);
134: base -= iscoloring->N;
135: PetscMemzero(mcolors,nc*sizeof(int));
136: for (i=0; i<n; i++) {
137: ii[colors[i]][mcolors[colors[i]]++] = i + base;
138: }
139: PetscMalloc((nc+1)*sizeof(IS),&is);
140: for (i=0; i<nc; i++) {
141: ISCreateGeneral(iscoloring->comm,mcolors[i],ii[i],is+i);
142: }
144: iscoloring->is = is;
145: PetscFree(ii[0]);
146: PetscFree(ii);
147: PetscFree(mcolors);
148: }
149: *isis = iscoloring->is;
150: }
152: return(0);
153: }
157: /*@C
158: ISColoringGetIS - Restores the index sets extracted from the coloring context
160: Collective on ISColoring
162: Input Parameter:
163: + iscoloring - the coloring context
164: - is - array of index sets
166: Level: advanced
168: .seealso: ISColoringGetIS(), ISColoringView()
169: @*/
170: int ISColoringRestoreIS(ISColoring iscoloring,IS *is[])
171: {
174:
175: /* currently nothing is done here */
177: return(0);
178: }
183: /*@C
184: ISColoringCreate - Generates an ISColoring context from lists (provided
185: by each processor) of colors for each node.
187: Collective on MPI_Comm
189: Input Parameters:
190: + comm - communicator for the processors creating the coloring
191: . n - number of nodes on this processor
192: - colors - array containing the colors for this processor, color
193: numbers begin at 0. In C/C++ this array must have been obtained with PetscMalloc()
194: and should NOT be freed (The ISColoringDestroy() will free it).
196: Output Parameter:
197: . iscoloring - the resulting coloring data structure
199: Options Database Key:
200: . -is_coloring_view - Activates ISColoringView()
202: Level: advanced
203:
204: Notes: By default sets coloring type to IS_COLORING_LOCAL
206: .seealso: MatColoringCreate(), ISColoringView(), ISColoringDestroy(), ISColoringSetType()
208: @*/
209: int ISColoringCreate(MPI_Comm comm,int n,const ISColoringValue colors[],ISColoring *iscoloring)
210: {
211: int ierr,size,rank,base,top,tag,nc,ncwork,i;
212: PetscTruth flg;
213: MPI_Status status;
216: PetscNew(struct _p_ISColoring,iscoloring);
217: PetscCommDuplicate(comm,&(*iscoloring)->comm,&tag);
218: comm = (*iscoloring)->comm;
220: /* compute the number of the first node on my processor */
221: MPI_Comm_size(comm,&size);
223: /* should use MPI_Scan() */
224: MPI_Comm_rank(comm,&rank);
225: if (!rank) {
226: base = 0;
227: top = n;
228: } else {
229: MPI_Recv(&base,1,MPI_INT,rank-1,tag,comm,&status);
230: top = base+n;
231: }
232: if (rank < size-1) {
233: MPI_Send(&top,1,MPI_INT,rank+1,tag,comm);
234: }
236: /* compute the total number of colors */
237: ncwork = 0;
238: for (i=0; i<n; i++) {
239: if (ncwork < colors[i]) ncwork = colors[i];
240: }
241: ncwork++;
242: MPI_Allreduce(&ncwork,&nc,1,MPI_INT,MPI_MAX,comm);
243: (*iscoloring)->n = nc;
244: (*iscoloring)->is = 0;
245: (*iscoloring)->colors = (ISColoringValue *)colors;
246: (*iscoloring)->N = n;
247: (*iscoloring)->refct = 1;
248: (*iscoloring)->ctype = IS_COLORING_LOCAL;
250: PetscOptionsHasName(PETSC_NULL,"-is_coloring_view",&flg);
251: if (flg) {
252: ISColoringView(*iscoloring,PETSC_VIEWER_STDOUT_((*iscoloring)->comm));
253: }
254: PetscLogInfo(0,"ISColoringCreate: Number of colors %d\n",nc);
255: return(0);
256: }
260: /*@C
261: ISPartitioningToNumbering - Takes an ISPartitioning and on each processor
262: generates an IS that contains a new global node number for each index based
263: on the partitioing.
265: Collective on IS
267: Input Parameters
268: . partitioning - a partitioning as generated by MatPartitioningApply()
270: Output Parameter:
271: . is - on each processor the index set that defines the global numbers
272: (in the new numbering) for all the nodes currently (before the partitioning)
273: on that processor
275: Level: advanced
277: .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningCount()
279: @*/
280: int ISPartitioningToNumbering(IS part,IS *is)
281: {
282: MPI_Comm comm;
283: int i,ierr,size,*indices,np,npt,n,*starts,*sums,*lsizes,*newi;
286: PetscObjectGetComm((PetscObject)part,&comm);
287: MPI_Comm_size(comm,&size);
289: /* count the number of partitions, i.e., virtual processors */
290: ISGetLocalSize(part,&n);
291: ISGetIndices(part,&indices);
292: np = 0;
293: for (i=0; i<n; i++) {
294: np = PetscMax(np,indices[i]);
295: }
296: MPI_Allreduce(&np,&npt,1,MPI_INT,MPI_MAX,comm);
297: np = npt+1; /* so that it looks like a MPI_Comm_size output */
299: /*
300: lsizes - number of elements of each partition on this particular processor
301: sums - total number of "previous" nodes for any particular partition
302: starts - global number of first element in each partition on this processor
303: */
304: PetscMalloc(3*np*sizeof(int),&lsizes);
305: starts = lsizes + np;
306: sums = starts + np;
307: PetscMemzero(lsizes,np*sizeof(int));
308: for (i=0; i<n; i++) {
309: lsizes[indices[i]]++;
310: }
311: MPI_Allreduce(lsizes,sums,np,MPI_INT,MPI_SUM,comm);
312: MPI_Scan(lsizes,starts,np,MPI_INT,MPI_SUM,comm);
313: for (i=0; i<np; i++) {
314: starts[i] -= lsizes[i];
315: }
316: for (i=1; i<np; i++) {
317: sums[i] += sums[i-1];
318: starts[i] += sums[i-1];
319: }
321: /*
322: For each local index give it the new global number
323: */
324: PetscMalloc((n+1)*sizeof(int),&newi);
325: for (i=0; i<n; i++) {
326: newi[i] = starts[indices[i]]++;
327: }
328: PetscFree(lsizes);
330: ISRestoreIndices(part,&indices);
331: ISCreateGeneral(comm,n,newi,is);
332: PetscFree(newi);
333: ISSetPermutation(*is);
334: return(0);
335: }
339: /*@C
340: ISPartitioningCount - Takes a ISPartitioning and determines the number of
341: resulting elements on each processor
343: Collective on IS
345: Input Parameters:
346: . partitioning - a partitioning as generated by MatPartitioningApply()
348: Output Parameter:
349: . count - array of length size, to contain the number of elements assigned
350: to each partition, where size is the number of partitions generated
351: (see notes below).
353: Level: advanced
355: Notes:
356: By default the number of partitions generated (and thus the length
357: of count) is the size of the communicator associated with IS,
358: but it can be set by MatPartitioningSetNParts. The resulting array
359: of lengths can for instance serve as input of PCBJacobiSetTotalBlocks.
362: .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningToNumbering(),
363: MatPartitioningSetNParts()
365: @*/
366: int ISPartitioningCount(IS part,int count[])
367: {
368: MPI_Comm comm;
369: int i,ierr,size,*indices,np,npt,n,*lsizes;
372: PetscObjectGetComm((PetscObject)part,&comm);
373: MPI_Comm_size(comm,&size);
375: /* count the number of partitions */
376: ISGetLocalSize(part,&n);
377: ISGetIndices(part,&indices);
378: np = 0;
379: for (i=0; i<n; i++) {
380: np = PetscMax(np,indices[i]);
381: }
382: MPI_Allreduce(&np,&npt,1,MPI_INT,MPI_MAX,comm);
383: np = npt+1; /* so that it looks like a MPI_Comm_size output */
385: /*
386: lsizes - number of elements of each partition on this particular processor
387: sums - total number of "previous" nodes for any particular partition
388: starts - global number of first element in each partition on this processor
389: */
390: PetscMalloc(np*sizeof(int),&lsizes);
391: PetscMemzero(lsizes,np*sizeof(int));
392: for (i=0; i<n; i++) {
393: lsizes[indices[i]]++;
394: }
395: ISRestoreIndices(part,&indices);
396: MPI_Allreduce(lsizes,count,np,MPI_INT,MPI_SUM,comm);
397: PetscFree(lsizes);
399: return(0);
400: }
404: /*@C
405: ISAllGather - Given an index set (IS) on each processor, generates a large
406: index set (same on each processor) by concatenating together each
407: processors index set.
409: Collective on IS
411: Input Parameter:
412: . is - the distributed index set
414: Output Parameter:
415: . isout - the concatenated index set (same on all processors)
417: Notes:
418: ISAllGather() is clearly not scalable for large index sets.
420: The IS created on each processor must be created with a common
421: communicator (e.g., PETSC_COMM_WORLD). If the index sets were created
422: with PETSC_COMM_SELF, this routine will not work as expected, since
423: each process will generate its own new IS that consists only of
424: itself.
426: Level: intermediate
428: Concepts: gather^index sets
429: Concepts: index sets^gathering to all processors
430: Concepts: IS^gathering to all processors
432: .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGatherIndices()
433: @*/
434: int ISAllGather(IS is,IS *isout)
435: {
436: int *indices,*sizes,size,*offsets,n,*lindices,i,N,ierr;
437: MPI_Comm comm;
443: PetscObjectGetComm((PetscObject)is,&comm);
444: MPI_Comm_size(comm,&size);
445: PetscMalloc(2*size*sizeof(int),&sizes);
446: offsets = sizes + size;
447:
448: ISGetLocalSize(is,&n);
449: MPI_Allgather(&n,1,MPI_INT,sizes,1,MPI_INT,comm);
450: offsets[0] = 0;
451: for (i=1;i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
452: N = offsets[size-1] + sizes[size-1];
454: PetscMalloc((N+1)*sizeof(int),&indices);
455: ISGetIndices(is,&lindices);
456: MPI_Allgatherv(lindices,n,MPI_INT,indices,sizes,offsets,MPI_INT,comm);
457: ISRestoreIndices(is,&lindices);
459: ISCreateGeneral(PETSC_COMM_SELF,N,indices,isout);
460: PetscFree(indices);
462: PetscFree(sizes);
463: return(0);
464: }
468: /*@C
469: ISAllGatherIndices - Given a a set of integers on each processor, generates a large
470: set (same on each processor) by concatenating together each processors integers
472: Collective on MPI_Comm
474: Input Parameter:
475: + comm - communicator to share the indices
476: . n - local size of set
477: - lindices - local indices
479: Output Parameter:
480: + outN - total number of indices
481: - outindices - all of the integers
483: Notes:
484: ISAllGatherIndices() is clearly not scalable for large index sets.
487: Level: intermediate
489: Concepts: gather^index sets
490: Concepts: index sets^gathering to all processors
491: Concepts: IS^gathering to all processors
493: .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather()
494: @*/
495: int ISAllGatherIndices(MPI_Comm comm,int n,const int lindices[],int *outN,int *outindices[])
496: {
497: int *indices,*sizes,size,*offsets,i,N,ierr;
500: MPI_Comm_size(comm,&size);
501: PetscMalloc(2*size*sizeof(int),&sizes);
502: offsets = sizes + size;
503:
504: MPI_Allgather(&n,1,MPI_INT,sizes,1,MPI_INT,comm);
505: offsets[0] = 0;
506: for (i=1;i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
507: N = offsets[size-1] + sizes[size-1];
508: PetscFree(sizes);
510: PetscMalloc((N+1)*sizeof(int),&indices);
511: MPI_Allgatherv((void*)lindices,n,MPI_INT,indices,sizes,offsets,MPI_INT,comm);
513: *outindices = indices;
514: if (outN) *outN = N;
515: return(0);
516: }
522: /*@C
523: ISAllGatherColors - Given a a set of colors on each processor, generates a large
524: set (same on each processor) by concatenating together each processors colors
526: Collective on MPI_Comm
528: Input Parameter:
529: + comm - communicator to share the indices
530: . n - local size of set
531: - lindices - local colors
533: Output Parameter:
534: + outN - total number of indices
535: - outindices - all of the colors
537: Notes:
538: ISAllGatherColors() is clearly not scalable for large index sets.
541: Level: intermediate
543: Concepts: gather^index sets
544: Concepts: index sets^gathering to all processors
545: Concepts: IS^gathering to all processors
547: .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather(), ISAllGatherIndices()
548: @*/
549: int ISAllGatherColors(MPI_Comm comm,int n,ISColoringValue *lindices,int *outN,ISColoringValue *outindices[])
550: {
551: ISColoringValue *indices;
552: int *sizes,size,*offsets,i,N,ierr;
555: MPI_Comm_size(comm,&size);
556: PetscMalloc(2*size*sizeof(int),&sizes);
557: offsets = sizes + size;
558:
559: MPI_Allgather(&n,1,MPI_INT,sizes,1,MPI_INT,comm);
560: offsets[0] = 0;
561: for (i=1;i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
562: N = offsets[size-1] + sizes[size-1];
563: PetscFree(sizes);
565: PetscMalloc((N+1)*sizeof(ISColoringValue),&indices);
566: MPI_Allgatherv(lindices,n,MPIU_COLORING_VALUE,indices,sizes,offsets,MPIU_COLORING_VALUE,comm);
568: *outindices = indices;
569: if (outN) *outN = N;
570: return(0);
571: }