Actual source code: partition.c

      1: #define PETSCMAT_DLL

     3:  #include src/mat/matimpl.h

      5: /* Logging support */
      6: PetscCookie PETSCMAT_DLLEXPORT MAT_PARTITIONING_COOKIE = 0;

      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(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(part->comm,&rank);

     26:   MatGetLocalSize(part->adj,&m,PETSC_NULL);
     27:   ISCreateStride(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(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(part->comm,rend-rstart,color,partitioning);
     63:   PetscFree(color);

     65:   return(0);
     66: }

     71: PetscErrorCode PETSCMAT_DLLEXPORT 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 PETSCMAT_DLLEXPORT 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:  #include petscsys.h

     98: PetscFList MatPartitioningList = 0;
     99: PetscTruth MatPartitioningRegisterAllCalled = PETSC_FALSE;

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

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

    117: /*@C
    118:    MatPartitioningRegisterDestroy - Frees the list of partitioning routines.

    120:   Not Collective

    122:   Level: developer

    124: .keywords: matrix, register, destroy

    126: .seealso: MatPartitioningRegisterDynamic(), MatPartitioningRegisterAll()
    127: @*/
    128: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningRegisterDestroy(void)
    129: {

    133:   if (MatPartitioningList) {
    134:     PetscFListDestroy(&MatPartitioningList);
    135:     MatPartitioningList = 0;
    136:   }
    137:   return(0);
    138: }

    142: /*@C
    143:    MatPartitioningGetType - Gets the Partitioning method type and name (as a string)
    144:         from the partitioning context.

    146:    Not collective

    148:    Input Parameter:
    149: .  partitioning - the partitioning context

    151:    Output Parameter:
    152: .  type - partitioner type

    154:    Level: intermediate

    156:    Not Collective

    158: .keywords: Partitioning, get, method, name, type
    159: @*/
    160: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningGetType(MatPartitioning partitioning,MatPartitioningType *type)
    161: {
    163:   *type = partitioning->type_name;
    164:   return(0);
    165: }

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

    174:    Not collective

    176:    Input Parameter:
    177: .  partitioning - the partitioning context
    178: .  n - the number of partitions

    180:    Level: intermediate

    182:    Not Collective

    184: .keywords: Partitioning, set

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

    197: /*@C
    198:    MatPartitioningApply - Gets a partitioning for a matrix.

    200:    Collective on Mat

    202:    Input Parameters:
    203: .  matp - the matrix partitioning object

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

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

    216:    Level: beginner

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

    220: .keywords: matrix, get, partitioning

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

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

    241:   PetscOptionsHasName(PETSC_NULL,"-mat_partitioning_view",&flag);
    242:   if (flag) {
    243:     MatPartitioningView(matp,PETSC_VIEWER_STDOUT_(matp->comm));
    244:     ISView(*partitioning,PETSC_VIEWER_STDOUT_(matp->comm));
    245:   }
    246:   return(0);
    247: }
    248:
    251: /*@C
    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 PETSCMAT_DLLEXPORT MatPartitioningSetAdjacency(MatPartitioning part,Mat adj)
    268: {
    272:   part->adj = adj;
    273:   return(0);
    274: }

    278: /*@C
    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 PETSCMAT_DLLEXPORT MatPartitioningDestroy(MatPartitioning part)
    293: {

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

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

    315: /*@C
    316:    MatPartitioningSetVertexWeights - Sets the weights for vertices for a partitioning.

    318:    Collective on Partitioning

    320:    Input Parameters:
    321: +  part - the partitioning context
    322: -  weights - the weights

    324:    Level: beginner

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

    330: .keywords: Partitioning, destroy, context

    332: .seealso: MatPartitioningCreate(), MatPartitioningSetType(), MatPartitioningSetPartitionWeights()
    333: @*/
    334: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningSetVertexWeights(MatPartitioning part,const PetscInt weights[])
    335: {

    341:   if (part->vertex_weights){
    342:     PetscFree(part->vertex_weights);
    343:   }
    344:   part->vertex_weights = (PetscInt*)weights;
    345:   return(0);
    346: }

    350: /*@C
    351:    MatPartitioningSetPartitionWeights - Sets the weights for each partition.

    353:    Collective on Partitioning

    355:    Input Parameters:
    356: +  part - the partitioning context
    357: -  weights - the weights

    359:    Level: beginner

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

    365: .keywords: Partitioning, destroy, context

    367: .seealso: MatPartitioningCreate(), MatPartitioningSetType(), MatPartitioningSetVertexWeights()
    368: @*/
    369: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningSetPartitionWeights(MatPartitioning part,const PetscReal weights[])
    370: {

    376:   if (part->part_weights){
    377:     PetscFree(part->part_weights);
    378:   }
    379:   part->part_weights = (PetscReal*)weights;
    380:   return(0);
    381: }

    385: /*@C
    386:    MatPartitioningCreate - Creates a partitioning context.

    388:    Collective on MPI_Comm

    390:    Input Parameter:
    391: .   comm - MPI communicator

    393:    Output Parameter:
    394: .  newp - location to put the context

    396:    Level: beginner

    398: .keywords: Partitioning, create, context

    400: .seealso: MatPartitioningSetType(), MatPartitioningApply(), MatPartitioningDestroy(),
    401:           MatPartitioningSetAdjacency()

    403: @*/
    404: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningCreate(MPI_Comm comm,MatPartitioning *newp)
    405: {
    406:   MatPartitioning part;
    407:   PetscErrorCode  ierr;
    408:   PetscMPIInt     size;

    411:   *newp          = 0;

    413:   PetscHeaderCreate(part,_p_MatPartitioning,struct _MatPartitioningOps,MAT_PARTITIONING_COOKIE,-1,"MatPartitioning",comm,MatPartitioningDestroy,
    414:                     MatPartitioningView);
    415:   part->type           = -1;
    416:   part->vertex_weights = PETSC_NULL;
    417:   part->part_weights   = PETSC_NULL;
    418:   MPI_Comm_size(comm,&size);
    419:   part->n = (PetscInt)size;

    421:   *newp = part;
    422:   return(0);
    423: }

    427: /*@C
    428:    MatPartitioningView - Prints the partitioning data structure.

    430:    Collective on MatPartitioning

    432:    Input Parameters:
    433: .  part - the partitioning context
    434: .  viewer - optional visualization context

    436:    Level: intermediate

    438:    Note:
    439:    The available visualization contexts include
    440: +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
    441: -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
    442:          output where only the first processor opens
    443:          the file.  All other processors send their
    444:          data to the first processor to print.

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

    449: .keywords: Partitioning, view

    451: .seealso: PetscViewerASCIIOpen()
    452: @*/
    453: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningView(MatPartitioning part,PetscViewer viewer)
    454: {
    456:   PetscTruth          iascii;
    457:   MatPartitioningType name;

    461:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(part->comm);

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

    476:   if (part->ops->view) {
    477:     PetscViewerASCIIPushTab(viewer);
    478:     (*part->ops->view)(part,viewer);
    479:     PetscViewerASCIIPopTab(viewer);
    480:   }

    482:   return(0);
    483: }

    487: /*@C
    488:    MatPartitioningSetType - Sets the type of partitioner to use

    490:    Collective on MatPartitioning

    492:    Input Parameter:
    493: .  part - the partitioning context.
    494: .  type - a known method

    496:    Options Database Command:
    497: $  -mat_partitioning_type  <type>
    498: $      Use -help for a list of available methods
    499: $      (for instance, parmetis)

    501:    Level: intermediate

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

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

    507: @*/
    508: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningSetType(MatPartitioning part,const MatPartitioningType type)
    509: {
    510:   PetscErrorCode ierr,(*r)(MatPartitioning);
    511:   PetscTruth match;

    517:   PetscTypeCompare((PetscObject)part,type,&match);
    518:   if (match) return(0);

    520:   if (part->setupcalled) {
    521:      (*part->ops->destroy)(part);
    522:     part->data        = 0;
    523:     part->setupcalled = 0;
    524:   }

    526:   /* Get the function pointers for the method requested */
    527:   if (!MatPartitioningRegisterAllCalled){ MatPartitioningRegisterAll(0);}
    528:    PetscFListFind(part->comm,MatPartitioningList,type,(void (**)(void)) &r);

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

    532:   part->ops->destroy      = (PetscErrorCode (*)(MatPartitioning)) 0;
    533:   part->ops->view         = (PetscErrorCode (*)(MatPartitioning,PetscViewer)) 0;
    534:   (*r)(part);

    536:   PetscStrfree(part->type_name);
    537:   PetscStrallocpy(type,&part->type_name);
    538:   return(0);
    539: }

    543: /*@
    544:    MatPartitioningSetFromOptions - Sets various partitioning options from the
    545:         options database.

    547:    Collective on MatPartitioning

    549:    Input Parameter:
    550: .  part - the partitioning context.

    552:    Options Database Command:
    553: $  -mat_partitioning_type  <type>
    554: $      Use -help for a list of available methods
    555: $      (for instance, parmetis)

    557:    Level: beginner

    559: .keywords: partitioning, set, method, type
    560: @*/
    561: PetscErrorCode PETSCMAT_DLLEXPORT MatPartitioningSetFromOptions(MatPartitioning part)
    562: {
    564:   PetscTruth flag;
    565:   char       type[256];
    566:   const char *def;

    569:   if (!MatPartitioningRegisterAllCalled){ MatPartitioningRegisterAll(0);}
    570:   PetscOptionsBegin(part->comm,part->prefix,"Partitioning options","MatOrderings");
    571:     if (!part->type_name) {
    572: #if defined(PETSC_HAVE_PARMETIS)
    573:       def = MAT_PARTITIONING_PARMETIS;
    574: #else
    575:       def = MAT_PARTITIONING_CURRENT;
    576: #endif
    577:     } else {
    578:       def = part->type_name;
    579:     }
    580:     PetscOptionsList("-mat_partitioning_type","Type of partitioner","MatPartitioningSetType",MatPartitioningList,def,type,256,&flag);
    581:     if (flag) {
    582:       MatPartitioningSetType(part,type);
    583:     }
    584:     /*
    585:       Set the type if it was never set.
    586:     */
    587:     if (!part->type_name) {
    588:       MatPartitioningSetType(part,def);
    589:     }

    591:     if (part->ops->setfromoptions) {
    592:       (*part->ops->setfromoptions)(part);
    593:     }
    594:   PetscOptionsEnd();
    595:   return(0);
    596: }