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