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
6: /*@C
7: ISColoringDestroy - Destroys a coloring context.
9: Collective on ISColoring
11: Input Parameter:
12: . iscoloring - the coloring context
14: Level: advanced
16: .seealso: ISColoringView(), MatGetColoring()
17: @*/
18: int ISColoringDestroy(ISColoring iscoloring)
19: {
20: int i,ierr;
24: if (--iscoloring->refct > 0) return(0);
26: if (iscoloring->is) {
27: for (i=0; i<iscoloring->n; i++) {
28: ISDestroy(iscoloring->is[i]);
29: }
30: PetscFree(iscoloring->is);
31: }
32: if (iscoloring->colors) {
33: PetscFree(iscoloring->colors);
34: }
35: PetscCommDestroy_Private(&iscoloring->comm);
36: PetscFree(iscoloring);
37: return(0);
38: }
40: /*@C
41: ISColoringView - Views a coloring context.
43: Collective on ISColoring
45: Input Parameters:
46: + iscoloring - the coloring context
47: - viewer - the viewer
49: Level: advanced
51: .seealso: ISColoringDestroy(), ISColoringGetIS(), MatGetColoring()
52: @*/
53: int ISColoringView(ISColoring iscoloring,PetscViewer viewer)
54: {
55: int i,ierr;
56: PetscTruth isascii;
57: IS *is;
61: if (!viewer) viewer = PETSC_VIEWER_STDOUT_(iscoloring->comm);
64: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
65: if (isascii) {
66: MPI_Comm comm;
67: int rank;
68: PetscObjectGetComm((PetscObject)viewer,&comm);
69: MPI_Comm_rank(comm,&rank);
70: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of colors %dn",rank,iscoloring->n);
71: PetscViewerFlush(viewer);
72: } else {
73: SETERRQ1(1,"Viewer type %s not supported for ISColoring",((PetscObject)viewer)->type_name);
74: }
76: ISColoringGetIS(iscoloring,PETSC_IGNORE,&is);
77: for (i=0; i<iscoloring->n; i++) {
78: ISView(iscoloring->is[i],viewer);
79: }
80: ISColoringRestoreIS(iscoloring,&is);
81: return(0);
82: }
84: /*@C
85: ISColoringGetIS - Extracts index sets from the coloring context
87: Collective on ISColoring
89: Input Parameter:
90: . iscoloring - the coloring context
92: Output Parameters:
93: + nn - number of index sets in the coloring context
94: - is - array of index sets
96: Level: advanced
98: .seealso: ISColoringRestoreIS(), ISColoringView()
99: @*/
100: int ISColoringGetIS(ISColoring iscoloring,int *nn,IS *isis[])
101: {
107: if (nn) *nn = iscoloring->n;
108: if (isis) {
109: if (!iscoloring->is) {
110: int *mcolors,**ii,nc = iscoloring->n,i,base, n = iscoloring->N;
111: int *colors = iscoloring->colors;
112: IS *is;
113:
114: /* generate the lists of nodes for each color */
115: PetscMalloc((nc+1)*sizeof(int),&mcolors);
116: PetscMemzero(mcolors,nc*sizeof(int));
117: for (i=0; i<n; i++) {
118: mcolors[colors[i]]++;
119: }
121: PetscMalloc((nc+1)*sizeof(int*),&ii);
122: PetscMalloc((n+1)*sizeof(int),&ii[0]);
123: for (i=1; i<nc; i++) {
124: ii[i] = ii[i-1] + mcolors[i-1];
125: }
126:
127: MPI_Scan(&iscoloring->N,&base,1,MPI_INT,MPI_SUM,iscoloring->comm);
128: base -= iscoloring->N;
129: PetscMemzero(mcolors,nc*sizeof(int));
130: for (i=0; i<n; i++) {
131: ii[colors[i]][mcolors[colors[i]]++] = i + base;
132: }
133: PetscMalloc((nc+1)*sizeof(IS),&is);
134: for (i=0; i<nc; i++) {
135: ISCreateGeneral(iscoloring->comm,mcolors[i],ii[i],is+i);
136: }
138: iscoloring->is = is;
139: PetscFree(ii[0]);
140: PetscFree(ii);
141: PetscFree(mcolors);
142: }
143: *isis = iscoloring->is;
144: }
146: return(0);
147: }
149: /*@C
150: ISColoringGetIS - Restores the index sets extracted from the coloring context
152: Collective on ISColoring
154: Input Parameter:
155: + iscoloring - the coloring context
156: - is - array of index sets
158: Level: advanced
160: .seealso: ISColoringGetIS(), ISColoringView()
161: @*/
162: int ISColoringRestoreIS(ISColoring iscoloring,IS *is[])
163: {
166:
167: /* currently nothing is done here */
169: return(0);
170: }
173: /*@C
174: ISColoringCreate - Generates an ISColoring context from lists (provided
175: by each processor) of colors for each node.
177: Collective on MPI_Comm
179: Input Parameters:
180: + comm - communicator for the processors creating the coloring
181: . n - number of nodes on this processor
182: - colors - array containing the colors for this processor, color
183: numbers begin at 0. In C/C++ this array must have been obtained with PetscMalloc()
184: and should NOT be freed (The ISColoringDestroy() will free it).
186: Output Parameter:
187: . iscoloring - the resulting coloring data structure
189: Options Database Key:
190: . -is_coloring_view - Activates ISColoringView()
192: Level: advanced
193:
194: Notes: By default sets coloring type to IS_COLORING_LOCAL
196: .seealso: MatColoringCreate(), ISColoringView(), ISColoringDestroy(), ISColoringSetType()
198: @*/
199: int ISColoringCreate(MPI_Comm comm,int n,const int colors[],ISColoring *iscoloring)
200: {
201: int ierr,size,rank,base,top,tag,nc,ncwork,i;
202: PetscTruth flg;
203: MPI_Status status;
206: PetscNew(struct _p_ISColoring,iscoloring);
207: PetscCommDuplicate_Private(comm,&(*iscoloring)->comm,&tag);
208: comm = (*iscoloring)->comm;
210: /* compute the number of the first node on my processor */
211: MPI_Comm_size(comm,&size);
213: /* should use MPI_Scan() */
214: MPI_Comm_rank(comm,&rank);
215: if (!rank) {
216: base = 0;
217: top = n;
218: } else {
219: MPI_Recv(&base,1,MPI_INT,rank-1,tag,comm,&status);
220: top = base+n;
221: }
222: if (rank < size-1) {
223: MPI_Send(&top,1,MPI_INT,rank+1,tag,comm);
224: }
226: /* compute the total number of colors */
227: ncwork = 0;
228: for (i=0; i<n; i++) {
229: if (ncwork < colors[i]) ncwork = colors[i];
230: }
231: ncwork++;
232: MPI_Allreduce(&ncwork,&nc,1,MPI_INT,MPI_MAX,comm);
233: (*iscoloring)->n = nc;
234: (*iscoloring)->is = 0;
235: (*iscoloring)->colors = (int *)colors;
236: (*iscoloring)->N = n;
237: (*iscoloring)->refct = 1;
238: (*iscoloring)->ctype = IS_COLORING_LOCAL;
240: PetscOptionsHasName(PETSC_NULL,"-is_coloring_view",&flg);
241: if (flg) {
242: ISColoringView(*iscoloring,PETSC_VIEWER_STDOUT_((*iscoloring)->comm));
243: }
244: PetscLogInfo(0,"ISColoringCreate: Number of colors %dn",nc);
245: return(0);
246: }
248: /*@C
249: ISPartitioningToNumbering - Takes an ISPartitioning and on each processor
250: generates an IS that contains a new global node number for each index based
251: on the partitioing.
253: Collective on IS
255: Input Parameters
256: . partitioning - a partitioning as generated by MatPartitioningApply()
258: Output Parameter:
259: . is - on each processor the index set that defines the global numbers
260: (in the new numbering) for all the nodes currently (before the partitioning)
261: on that processor
263: Level: advanced
265: .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartioningCount()
267: @*/
268: int ISPartitioningToNumbering(IS part,IS *is)
269: {
270: MPI_Comm comm;
271: int i,ierr,size,*indices,np,n,*starts,*sums,*lsizes,*newi;
274: PetscObjectGetComm((PetscObject)part,&comm);
275: MPI_Comm_size(comm,&size);
277: /* count the number of partitions, make sure <= size */
278: ISGetLocalSize(part,&n);
279: ISGetIndices(part,&indices);
280: np = 0;
281: for (i=0; i<n; i++) {
282: np = PetscMax(np,indices[i]);
283: }
284: if (np >= size) {
285: SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Number of partitions %d larger than number of processors %d",np,size);
286: }
288: /*
289: lsizes - number of elements of each partition on this particular processor
290: sums - total number of "previous" nodes for any particular partition
291: starts - global number of first element in each partition on this processor
292: */
293: ierr = PetscMalloc(3*size*sizeof(int),&lsizes);
294: starts = lsizes + size;
295: sums = starts + size;
296: ierr = PetscMemzero(lsizes,size*sizeof(int));
297: for (i=0; i<n; i++) {
298: lsizes[indices[i]]++;
299: }
300: MPI_Allreduce(lsizes,sums,size,MPI_INT,MPI_SUM,comm);
301: MPI_Scan(lsizes,starts,size,MPI_INT,MPI_SUM,comm);
302: for (i=0; i<size; i++) {
303: starts[i] -= lsizes[i];
304: }
305: for (i=1; i<size; i++) {
306: sums[i] += sums[i-1];
307: starts[i] += sums[i-1];
308: }
310: /*
311: For each local index give it the new global number
312: */
313: PetscMalloc((n+1)*sizeof(int),&newi);
314: for (i=0; i<n; i++) {
315: newi[i] = starts[indices[i]]++;
316: }
317: PetscFree(lsizes);
319: ISRestoreIndices(part,&indices);
320: ISCreateGeneral(comm,n,newi,is);
321: PetscFree(newi);
322: ISSetPermutation(*is);
323: return(0);
324: }
326: /*@C
327: ISPartitioningCount - Takes a ISPartitioning and determines the number of
328: resulting elements on each processor
330: Collective on IS
332: Input Parameters:
333: . partitioning - a partitioning as generated by MatPartitioningApply()
335: Output Parameter:
336: . count - array of length size of communicator associated with IS, contains
337: the number of elements assigned to each processor
339: Level: advanced
341: .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningToNumbering()
343: @*/
344: int ISPartitioningCount(IS part,int count[])
345: {
346: MPI_Comm comm;
347: int i,ierr,size,*indices,np,n,*lsizes;
350: PetscObjectGetComm((PetscObject)part,&comm);
351: MPI_Comm_size(comm,&size);
353: /* count the number of partitions,make sure <= size */
354: ISGetLocalSize(part,&n);
355: ISGetIndices(part,&indices);
356: np = 0;
357: for (i=0; i<n; i++) {
358: np = PetscMax(np,indices[i]);
359: }
360: if (np >= size) {
361: SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Number of partitions %d larger than number of processors %d",np,size);
362: }
364: /*
365: lsizes - number of elements of each partition on this particular processor
366: sums - total number of "previous" nodes for any particular partition
367: starts - global number of first element in each partition on this processor
368: */
369: PetscMalloc(size*sizeof(int),&lsizes);
370: ierr = PetscMemzero(lsizes,size*sizeof(int));
371: for (i=0; i<n; i++) {
372: lsizes[indices[i]]++;
373: }
374: ISRestoreIndices(part,&indices);
375: MPI_Allreduce(lsizes,count,size,MPI_INT,MPI_SUM,comm);
376: PetscFree(lsizes);
378: return(0);
379: }
381: /*@C
382: ISAllGather - Given an index set (IS) on each processor, generates a large
383: index set (same on each processor) by concatenating together each
384: processors index set.
386: Collective on IS
388: Input Parameter:
389: . is - the distributed index set
391: Output Parameter:
392: . isout - the concatenated index set (same on all processors)
394: Notes:
395: ISAllGather() is clearly not scalable for large index sets.
397: The IS created on each processor must be created with a common
398: communicator (e.g., PETSC_COMM_WORLD). If the index sets were created
399: with PETSC_COMM_SELF, this routine will not work as expected, since
400: each process will generate its own new IS that consists only of
401: itself.
403: Level: intermediate
405: Concepts: gather^index sets
406: Concepts: index sets^gathering to all processors
407: Concepts: IS^gathering to all processors
409: .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGatherIndices()
410: @*/
411: int ISAllGather(IS is,IS *isout)
412: {
413: int *indices,*sizes,size,*offsets,n,*lindices,i,N,ierr;
414: MPI_Comm comm;
419: PetscObjectGetComm((PetscObject)is,&comm);
420: MPI_Comm_size(comm,&size);
421: PetscMalloc(2*size*sizeof(int),&sizes);
422: offsets = sizes + size;
423:
424: ISGetLocalSize(is,&n);
425: MPI_Allgather(&n,1,MPI_INT,sizes,1,MPI_INT,comm);
426: offsets[0] = 0;
427: for (i=1;i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
428: N = offsets[size-1] + sizes[size-1];
430: PetscMalloc((N+1)*sizeof(int),&indices);
431: ISGetIndices(is,&lindices);
432: MPI_Allgatherv(lindices,n,MPI_INT,indices,sizes,offsets,MPI_INT,comm);
433: ISRestoreIndices(is,&lindices);
435: ISCreateGeneral(PETSC_COMM_SELF,N,indices,isout);
436: PetscFree(indices);
438: PetscFree(sizes);
439: return(0);
440: }
442: /*@C
443: ISAllGatherIndices - Given a a set of integers on each processor, generates a large
444: set (same on each processor) by concatenating together each processors integers
446: Collective on MPI_Comm
448: Input Parameter:
449: + comm - communicator to share the indices
450: . n - local size of set
451: - lindices - local indices
453: Output Parameter:
454: + outN - total number of indices
455: - outindices - all of the integers
457: Notes:
458: ISAllGatherIndices() is clearly not scalable for large index sets.
461: Level: intermediate
463: Concepts: gather^index sets
464: Concepts: index sets^gathering to all processors
465: Concepts: IS^gathering to all processors
467: .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather()
468: @*/
469: int ISAllGatherIndices(MPI_Comm comm,int n,int *lindices,int *outN,int **outindices)
470: {
471: int *indices,*sizes,size,*offsets,i,N,ierr;
474: MPI_Comm_size(comm,&size);
475: PetscMalloc(2*size*sizeof(int),&sizes);
476: offsets = sizes + size;
477:
478: MPI_Allgather(&n,1,MPI_INT,sizes,1,MPI_INT,comm);
479: offsets[0] = 0;
480: for (i=1;i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
481: N = offsets[size-1] + sizes[size-1];
482: PetscFree(sizes);
484: PetscMalloc((N+1)*sizeof(int),&indices);
485: MPI_Allgatherv(lindices,n,MPI_INT,indices,sizes,offsets,MPI_INT,comm);
487: *outindices = indices;
488: if (outN) *outN = N;
489: return(0);
490: }