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: }