Actual source code: partition.c

  1: #define PETSCMAT_DLL

 3:  #include private/matimpl.h

  5: /* Logging support */
  6: PetscCookie  MAT_PARTITIONING_COOKIE;

  8: /*
  9:    Simplest partitioning, keeps the current partitioning.
 10: */
 13: static PetscErrorCode MatPartitioningApply_Current(MatPartitioning part,IS *partitioning)
 14: {
 16:   PetscInt       m;
 17:   PetscMPIInt    rank,size;

 20:   MPI_Comm_size(((PetscObject)part)->comm,&size);
 21:   if (part->n != size) {
 22:     SETERRQ(PETSC_ERR_SUP,"This is the DEFAULT NO-OP partitioner, it currently only supports one domain per processor\nuse -matpartitioning_type parmetis or chaco or scotch for more than one subdomain per processor");
 23:   }
 24:   MPI_Comm_rank(((PetscObject)part)->comm,&rank);

 26:   MatGetLocalSize(part->adj,&m,PETSC_NULL);
 27:   ISCreateStride(((PetscObject)part)->comm,m,rank,0,partitioning);
 28:   return(0);
 29: }

 33: static PetscErrorCode MatPartitioningApply_Square(MatPartitioning part,IS *partitioning)
 34: {
 36:   PetscInt       cell,n,N,p,rstart,rend,*color;
 37:   PetscMPIInt    size;

 40:   MPI_Comm_size(((PetscObject)part)->comm,&size);
 41:   if (part->n != size) {
 42:     SETERRQ(PETSC_ERR_SUP,"Currently only supports one domain per processor");
 43:   }
 44:   p = (PetscInt)sqrt((double)part->n);
 45:   if (p*p != part->n) {
 46:     SETERRQ(PETSC_ERR_SUP,"Square partitioning requires \"perfect square\" number of domains");
 47:   }
 48:   MatGetSize(part->adj,&N,PETSC_NULL);
 49:   n = (PetscInt)sqrt((double)N);
 50:   if (n*n != N) {  /* This condition is NECESSARY, but NOT SUFFICIENT in order to the domain be square */
 51:     SETERRQ(PETSC_ERR_SUP,"Square partitioning requires square domain");
 52:   }
 53:   if (n%p != 0) {
 54:     SETERRQ(PETSC_ERR_SUP,"Square partitioning requires p to divide n");
 55:   }
 56:   MatGetOwnershipRange(part->adj,&rstart,&rend);
 57:   PetscMalloc((rend-rstart)*sizeof(PetscInt),&color);
 58:   /* for (int cell=rstart; cell<rend; cell++) { color[cell-rstart] = ((cell%n) < (n/2)) + 2 * ((cell/n) < (n/2)); } */
 59:   for (cell=rstart; cell<rend; cell++) {
 60:     color[cell-rstart] = ((cell%n) / (n/p)) + p * ((cell/n) / (n/p));
 61:   }
 62:   ISCreateGeneral(((PetscObject)part)->comm,rend-rstart,color,partitioning);
 63:   PetscFree(color);

 65:   return(0);
 66: }

 71: PetscErrorCode  MatPartitioningCreate_Current(MatPartitioning part)
 72: {
 74:   part->ops->apply   = MatPartitioningApply_Current;
 75:   part->ops->view    = 0;
 76:   part->ops->destroy = 0;
 77:   return(0);
 78: }

 84: PetscErrorCode  MatPartitioningCreate_Square(MatPartitioning part)
 85: {
 87:   part->ops->apply   = MatPartitioningApply_Square;
 88:   part->ops->view    = 0;
 89:   part->ops->destroy = 0;
 90:   return(0);
 91: }

 94: /* ===========================================================================================*/

 96: PetscFList MatPartitioningList = 0;
 97: PetscTruth MatPartitioningRegisterAllCalled = PETSC_FALSE;


102: PetscErrorCode  MatPartitioningRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatPartitioning))
103: {
105:   char fullname[PETSC_MAX_PATH_LEN];

108:   PetscFListConcat(path,name,fullname);
109:   PetscFListAdd(&MatPartitioningList,sname,fullname,(void (*)(void))function);
110:   return(0);
111: }

115: /*@C
116:    MatPartitioningRegisterDestroy - Frees the list of partitioning routines.

118:   Not Collective

120:   Level: developer

122: .keywords: matrix, register, destroy

124: .seealso: MatPartitioningRegisterDynamic(), MatPartitioningRegisterAll()
125: @*/
126: PetscErrorCode  MatPartitioningRegisterDestroy(void)
127: {

131:   MatPartitioningRegisterAllCalled = PETSC_FALSE;
132:   PetscFListDestroy(&MatPartitioningList);
133:   return(0);
134: }

138: /*@C
139:    MatPartitioningGetType - Gets the Partitioning method type and name (as a string) 
140:         from the partitioning context.

142:    Not collective

144:    Input Parameter:
145: .  partitioning - the partitioning context

147:    Output Parameter:
148: .  type - partitioner type

150:    Level: intermediate

152:    Not Collective

154: .keywords: Partitioning, get, method, name, type
155: @*/
156: PetscErrorCode  MatPartitioningGetType(MatPartitioning partitioning,const MatPartitioningType *type)
157: {
161:   *type = ((PetscObject)partitioning)->type_name;
162:   return(0);
163: }

167: /*@C
168:    MatPartitioningSetNParts - Set how many partitions need to be created;
169:         by default this is one per processor. Certain partitioning schemes may
170:         in fact only support that option.

172:    Not collective

174:    Input Parameter:
175: .  partitioning - the partitioning context
176: .  n - the number of partitions

178:    Level: intermediate

180:    Not Collective

182: .keywords: Partitioning, set

184: .seealso: MatPartitioningCreate(), MatPartitioningApply()
185: @*/
186: PetscErrorCode  MatPartitioningSetNParts(MatPartitioning part,PetscInt n)
187: {
189:   part->n = n;
190:   return(0);
191: }

195: /*@
196:    MatPartitioningApply - Gets a partitioning for a matrix.

198:    Collective on Mat

200:    Input Parameters:
201: .  matp - the matrix partitioning object

203:    Output Parameters:
204: .   partitioning - the partitioning. For each local node this tells the processor
205:                    number that that node is assigned to.

207:    Options Database Keys:
208:    To specify the partitioning through the options database, use one of
209:    the following 
210: $    -mat_partitioning_type parmetis, -mat_partitioning current
211:    To see the partitioning result
212: $    -mat_partitioning_view

214:    Level: beginner

216:    The user can define additional partitionings; see MatPartitioningRegisterDynamic().

218: .keywords: matrix, get, partitioning

220: .seealso:  MatPartitioningRegisterDynamic(), MatPartitioningCreate(),
221:            MatPartitioningDestroy(), MatPartitioningSetAdjacency(), ISPartitioningToNumbering(),
222:            ISPartitioningCount()
223: @*/
224: PetscErrorCode  MatPartitioningApply(MatPartitioning matp,IS *partitioning)
225: {
227:   PetscTruth     flag = PETSC_FALSE;

232:   if (!matp->adj->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
233:   if (matp->adj->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
234:   if (!matp->ops->apply) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set type with MatPartitioningSetFromOptions() or MatPartitioningSetType()");
235:   PetscLogEventBegin(MAT_Partitioning,matp,0,0,0);
236:   (*matp->ops->apply)(matp,partitioning);
237:   PetscLogEventEnd(MAT_Partitioning,matp,0,0,0);

239:   PetscOptionsGetTruth(PETSC_NULL,"-mat_partitioning_view",&flag,PETSC_NULL);
240:   if (flag) {
241:     PetscViewer viewer;
242:     PetscViewerASCIIGetStdout(((PetscObject)matp)->comm,&viewer);
243:     MatPartitioningView(matp,viewer);
244:     ISView(*partitioning,viewer);
245:   }
246:   return(0);
247: }
248: 
251: /*@
252:    MatPartitioningSetAdjacency - Sets the adjacency graph (matrix) of the thing to be
253:       partitioned.

255:    Collective on MatPartitioning and Mat

257:    Input Parameters:
258: +  part - the partitioning context
259: -  adj - the adjacency matrix

261:    Level: beginner

263: .keywords: Partitioning, adjacency

265: .seealso: MatPartitioningCreate()
266: @*/
267: PetscErrorCode  MatPartitioningSetAdjacency(MatPartitioning part,Mat adj)
268: {
272:   part->adj = adj;
273:   return(0);
274: }

278: /*@
279:    MatPartitioningDestroy - Destroys the partitioning context.

281:    Collective on Partitioning

283:    Input Parameters:
284: .  part - the partitioning context

286:    Level: beginner

288: .keywords: Partitioning, destroy, context

290: .seealso: MatPartitioningCreate()
291: @*/
292: PetscErrorCode  MatPartitioningDestroy(MatPartitioning part)
293: {

298:   if (--((PetscObject)part)->refct > 0) return(0);

300:   if (part->ops->destroy) {
301:     (*part->ops->destroy)(part);
302:   }
303:   PetscFree(part->vertex_weights);
304:   PetscFree(part->part_weights);
305:   PetscHeaderDestroy(part);
306:   return(0);
307: }

311: /*@C
312:    MatPartitioningSetVertexWeights - Sets the weights for vertices for a partitioning.

314:    Collective on Partitioning

316:    Input Parameters:
317: +  part - the partitioning context
318: -  weights - the weights

320:    Level: beginner

322:    Notes:
323:       The array weights is freed by PETSc so the user should not free the array. In C/C++
324:    the array must be obtained with a call to PetscMalloc(), not malloc().

326: .keywords: Partitioning, destroy, context

328: .seealso: MatPartitioningCreate(), MatPartitioningSetType(), MatPartitioningSetPartitionWeights()
329: @*/
330: PetscErrorCode  MatPartitioningSetVertexWeights(MatPartitioning part,const PetscInt weights[])
331: {


337:   PetscFree(part->vertex_weights);
338:   part->vertex_weights = (PetscInt*)weights;
339:   return(0);
340: }

344: /*@C
345:    MatPartitioningSetPartitionWeights - Sets the weights for each partition.

347:    Collective on Partitioning

349:    Input Parameters:
350: +  part - the partitioning context
351: -  weights - the weights

353:    Level: beginner

355:    Notes:
356:       The array weights is freed by PETSc so the user should not free the array. In C/C++
357:    the array must be obtained with a call to PetscMalloc(), not malloc().

359: .keywords: Partitioning, destroy, context

361: .seealso: MatPartitioningCreate(), MatPartitioningSetType(), MatPartitioningSetVertexWeights()
362: @*/
363: PetscErrorCode  MatPartitioningSetPartitionWeights(MatPartitioning part,const PetscReal weights[])
364: {


370:   PetscFree(part->part_weights);
371:   part->part_weights = (PetscReal*)weights;
372:   return(0);
373: }

377: /*@
378:    MatPartitioningCreate - Creates a partitioning context.

380:    Collective on MPI_Comm

382:    Input Parameter:
383: .   comm - MPI communicator 

385:    Output Parameter:
386: .  newp - location to put the context

388:    Level: beginner

390: .keywords: Partitioning, create, context

392: .seealso: MatPartitioningSetType(), MatPartitioningApply(), MatPartitioningDestroy(),
393:           MatPartitioningSetAdjacency()

395: @*/
396: PetscErrorCode  MatPartitioningCreate(MPI_Comm comm,MatPartitioning *newp)
397: {
398:   MatPartitioning part;
399:   PetscErrorCode  ierr;
400:   PetscMPIInt     size;

403:   *newp          = 0;

405: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
406:   MatInitializePackage(PETSC_NULL);
407: #endif
408:   PetscHeaderCreate(part,_p_MatPartitioning,struct _MatPartitioningOps,MAT_PARTITIONING_COOKIE,-1,"MatPartitioning",comm,MatPartitioningDestroy,
409:                     MatPartitioningView);
410:   part->vertex_weights = PETSC_NULL;
411:   part->part_weights   = PETSC_NULL;
412:   MPI_Comm_size(comm,&size);
413:   part->n = (PetscInt)size;

415:   *newp = part;
416:   return(0);
417: }

421: /*@C 
422:    MatPartitioningView - Prints the partitioning data structure.

424:    Collective on MatPartitioning

426:    Input Parameters:
427: .  part - the partitioning context
428: .  viewer - optional visualization context

430:    Level: intermediate

432:    Note:
433:    The available visualization contexts include
434: +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
435: -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
436:          output where only the first processor opens
437:          the file.  All other processors send their 
438:          data to the first processor to print. 

440:    The user can open alternative visualization contexts with
441: .     PetscViewerASCIIOpen() - output to a specified file

443: .keywords: Partitioning, view

445: .seealso: PetscViewerASCIIOpen()
446: @*/
447: PetscErrorCode  MatPartitioningView(MatPartitioning part,PetscViewer viewer)
448: {
449:   PetscErrorCode            ierr;
450:   PetscTruth                iascii;
451:   const MatPartitioningType name;

455:   if (!viewer) {
456:     PetscViewerASCIIGetStdout(((PetscObject)part)->comm,&viewer);
457:   }

461:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
462:   if (iascii) {
463:     MatPartitioningGetType(part,&name);
464:     PetscViewerASCIIPrintf(viewer,"MatPartitioning Object: %s\n",name);
465:     if (part->vertex_weights) {
466:       PetscViewerASCIIPrintf(viewer,"  Using vertex weights\n");
467:     }
468:   } else {
469:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for this MatParitioning",((PetscObject)viewer)->type_name);
470:   }

472:   if (part->ops->view) {
473:     PetscViewerASCIIPushTab(viewer);
474:     (*part->ops->view)(part,viewer);
475:     PetscViewerASCIIPopTab(viewer);
476:   }

478:   return(0);
479: }

483: /*@C
484:    MatPartitioningSetType - Sets the type of partitioner to use

486:    Collective on MatPartitioning

488:    Input Parameter:
489: .  part - the partitioning context.
490: .  type - a known method

492:    Options Database Command:
493: $  -mat_partitioning_type  <type>
494: $      Use -help for a list of available methods
495: $      (for instance, parmetis)

497:    Level: intermediate

499: .keywords: partitioning, set, method, type

501: .seealso: MatPartitioningCreate(), MatPartitioningApply(), MatPartitioningType

503: @*/
504: PetscErrorCode  MatPartitioningSetType(MatPartitioning part,const MatPartitioningType type)
505: {
506:   PetscErrorCode ierr,(*r)(MatPartitioning);
507:   PetscTruth match;


513:   PetscTypeCompare((PetscObject)part,type,&match);
514:   if (match) return(0);

516:   if (part->setupcalled) {
517:      (*part->ops->destroy)(part);
518:     part->data        = 0;
519:     part->setupcalled = 0;
520:   }

522:    PetscFListFind(MatPartitioningList,((PetscObject)part)->comm,type,(void (**)(void)) &r);

524:   if (!r) {SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown partitioning type %s",type);}

526:   part->ops->destroy      = (PetscErrorCode (*)(MatPartitioning)) 0;
527:   part->ops->view         = (PetscErrorCode (*)(MatPartitioning,PetscViewer)) 0;
528:   (*r)(part);

530:   PetscStrfree(((PetscObject)part)->type_name);
531:   PetscStrallocpy(type,&((PetscObject)part)->type_name);
532:   return(0);
533: }

537: /*@
538:    MatPartitioningSetFromOptions - Sets various partitioning options from the 
539:         options database.

541:    Collective on MatPartitioning

543:    Input Parameter:
544: .  part - the partitioning context.

546:    Options Database Command:
547: $  -mat_partitioning_type  <type>
548: $      Use -help for a list of available methods
549: $      (for instance, parmetis)

551:    Level: beginner

553: .keywords: partitioning, set, method, type
554: @*/
555: PetscErrorCode  MatPartitioningSetFromOptions(MatPartitioning part)
556: {
558:   PetscTruth flag;
559:   char       type[256];
560:   const char *def;

563:   PetscOptionsBegin(((PetscObject)part)->comm,((PetscObject)part)->prefix,"Partitioning options","MatOrderings");
564:     if (!((PetscObject)part)->type_name) {
565: #if defined(PETSC_HAVE_PARMETIS)
566:       def = MAT_PARTITIONING_PARMETIS;
567: #else
568:       def = MAT_PARTITIONING_CURRENT;
569: #endif
570:     } else {
571:       def = ((PetscObject)part)->type_name;
572:     }
573:     PetscOptionsList("-mat_partitioning_type","Type of partitioner","MatPartitioningSetType",MatPartitioningList,def,type,256,&flag);
574:     if (flag) {
575:       MatPartitioningSetType(part,type);
576:     }
577:     /*
578:       Set the type if it was never set.
579:     */
580:     if (!((PetscObject)part)->type_name) {
581:       MatPartitioningSetType(part,def);
582:     }

584:     if (part->ops->setfromoptions) {
585:       (*part->ops->setfromoptions)(part);
586:     }
587:   PetscOptionsEnd();
588:   return(0);
589: }