예제 #1
0
    ParMetisGraph::ParMetisGraph(ParMetisMesh* parMesh,
                                 MPI::Intracomm* comm,
                                 int ncommonnodes)
      : parMetisMesh(parMesh)
    {
      FUNCNAME("ParMetisGraph::ParMetisGraph()");

      TEST_EXIT(parMesh)("No ParMetisMesh defined!\n");
      TEST_EXIT(comm)("No MPI communicator defined!\n");

      int numflag = 0;

      if (ncommonnodes == -1)
        ncommonnodes = parMetisMesh->getDim();

      MPI_Comm tmpComm = MPI_Comm(*comm);

      ParMETIS_V3_Mesh2Dual(parMetisMesh->getElementDist(),
                            parMetisMesh->getElementPtr(),
                            parMetisMesh->getElementInd(),
                            &numflag,
                            &ncommonnodes,
                            &xadj,
                            &adjncy,
                            &tmpComm);
    }
예제 #2
0
파일: pmetis.c 프로젝트: erdc-cm/petsc-dev
/*@
     MatMeshToCellGraph -   Uses the ParMETIS package to convert a Mat that represents a mesh to a Mat the represents the graph of the coupling
                       between cells (the "dual" graph) and is suitable for partitioning with the MatPartitioning object. Use this to partition
                       cells of a mesh.

   Collective on Mat

   Input Parameter:
+     mesh - the graph that represents the mesh
-     ncommonnodes - mesh elements that share this number of common nodes are considered neighbors, use 2 for triangules and
                     quadralaterials, 3 for tetrahedrals and 4 for hexahedrals

   Output Parameter:
.     dual - the dual graph

   Notes:
     Currently requires ParMetis to be installed and uses ParMETIS_V3_Mesh2Dual()

     The columns of each row of the Mat mesh are the global vertex numbers of the vertices of that rows cell. The number of rows in mesh is
     number of cells, the number of columns is the number of vertices.


   Level: advanced

.seealso: MatMeshToVertexGraph(), MatCreateMPIAdj(), MatPartitioningCreate()


@*/
PetscErrorCode MatMeshToCellGraph(Mat mesh,PetscInt ncommonnodes,Mat *dual)
{
  PetscErrorCode           ierr;
  PetscInt                 *newxadj,*newadjncy;
  PetscInt                 numflag=0;
  Mat_MPIAdj               *adj = (Mat_MPIAdj *)mesh->data,*newadj;
  PetscBool                flg;
  int                      status;

  PetscFunctionBegin;
  ierr = PetscObjectTypeCompare((PetscObject)mesh,MATMPIADJ,&flg);CHKERRQ(ierr);
  if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Must use MPIAdj matrix type");

  CHKMEMQ;
  status = ParMETIS_V3_Mesh2Dual(mesh->rmap->range,adj->i,adj->j,&numflag,&ncommonnodes,&newxadj,&newadjncy,&((PetscObject)mesh)->comm);CHKERRQPARMETIS(status);
  CHKMEMQ;
  ierr = MatCreateMPIAdj(((PetscObject)mesh)->comm,mesh->rmap->n,mesh->rmap->N,newxadj,newadjncy,PETSC_NULL,dual);CHKERRQ(ierr);
  newadj = (Mat_MPIAdj *)(*dual)->data;
  newadj->freeaijwithfree = PETSC_TRUE; /* signal the matrix should be freed with system free since space was allocated by ParMETIS */
  PetscFunctionReturn(0);
}
예제 #3
0
void
ParmetisLoadBalancer :: calculateLoadTransfer()
{
    idx_t *eind, *eptr, *xadj, *adjncy, *vwgt, *vsize;
    idx_t *part;
    int i, nlocalelems, eind_size, nelem = domain->giveNumberOfElements();
    int ndofman, idofman, numflag, ncommonnodes, options [ 4 ], ie, nproc;
    int edgecut, wgtflag, ncon;
    real_t ubvec [ 1 ], itr;
    Element *ielem;
    MPI_Comm communicator = MPI_COMM_WORLD;
    LoadBalancerMonitor *lbm = domain->giveEngngModel()->giveLoadBalancerMonitor();

    nproc = domain->giveEngngModel()->giveNumberOfProcesses();
    // init parmetis element numbering
    this->initGlobalParmetisElementNumbering();
    // prepare data structures for ParMETIS_V3_Mesh2Dual
    // count the size of eind array
    eind_size = 0;
    nlocalelems = 0;
    for ( i = 1; i <= nelem; i++ ) {
        ielem = domain->giveElement(i);
        if ( ielem->giveParallelMode() == Element_local ) {
            nlocalelems++;
            eind_size += ielem->giveNumberOfDofManagers();
        }
    }

    // allocate eind and eptr arrays
    eind = new idx_t [ eind_size ];
    eptr = new idx_t [ nlocalelems + 1 ];
    if ( ( eind == NULL ) || ( eptr == NULL ) ) {
        OOFEM_ERROR("failed to allocate eind and eptr arrays");
    }

    // fill in the eind and eptr (mesh graph)
    int eind_pos = 0, eptr_pos = 0;
    for ( i = 1; i <= nelem; i++ ) {
        ielem = domain->giveElement(i);
        if ( ielem->giveParallelMode() == Element_local ) {
            eptr [ eptr_pos ] = eind_pos;
            ndofman = ielem->giveNumberOfDofManagers();
            for ( idofman = 1; idofman <= ndofman; idofman++ ) {
                eind [ eind_pos++ ] = ielem->giveDofManager(idofman)->giveGlobalNumber() - 1;
            }

            eptr_pos++;
        }
    }

    // last rec
    eptr [ nlocalelems ] = eind_pos;

    // call ParMETIS_V3_Mesh2Dual to construct dual graph (in parallel)
    // dual graph: elements are vertices; element edges are graph edges
    // this is necessary, since cut runs through graph edges
    numflag = 0;
    ncommonnodes = 2;
    ParMETIS_V3_Mesh2Dual(elmdist, eptr, eind, & numflag, & ncommonnodes, & xadj, & adjncy, & communicator);

 #ifdef ParmetisLoadBalancer_DEBUG_PRINT
    int myrank = domain->giveEngngModel()->giveRank();
    // DEBUG PRINT
    fprintf(stderr, "[%d] xadj:", myrank);
    for ( i = 0; i <= nlocalelems; i++ ) {
        fprintf(stderr, " %d", xadj [ i ]);
    }

    fprintf(stderr, "\n[%d] adjncy:", myrank);
    for ( i = 0; i < xadj [ nlocalelems ]; i++ ) {
        fprintf(stderr, " %d", adjncy [ i ]);
    }

    fprintf(stderr, "\n");
 #endif


    // setup imbalance tolerance for each vertex weight - ubvec param
    ubvec [ 0 ] = 1.05;
    // setup options array
    options [ 0 ] = 1; // set to zero for default
    options [ 1 ] = 1; // get timings
    options [ 2 ] = 15; // random seed
    options [ 3 ] = 1; // sub-domains and processors are coupled
    // set ratio of inter-proc communication compared to data redistribution time
    itr = 1000.0;
    // set partition weights by quering load balance monitor
    const FloatArray &_procweights = lbm->giveProcessorWeights();
    if ( tpwgts == NULL ) {
        if ( ( tpwgts = new real_t [ nproc ] ) == NULL ) {
            OOFEM_ERROR("failed to allocate tpwgts");
        }
    }

    for ( i = 0; i < nproc; i++ ) {
        tpwgts [ i ] = _procweights(i);
    }

    /*
     * // log processor weights
     * OOFEM_LOG_RELEVANT ("[%d] ParmetisLoadBalancer: proc weights: ", myrank);
     * for (i=0; i<nproc; i++) OOFEM_LOG_RELEVANT ("%4.3f ",tpwgts[i]);
     * OOFEM_LOG_RELEVANT ("\n");
     */

    // obtain vertices weights (element weights) representing relative computational cost
    if ( ( vwgt = new idx_t [ nlocalelems ] ) == NULL ) {
        OOFEM_ERROR("failed to allocate vwgt");
    }

    if ( ( vsize = new idx_t [ nlocalelems ] ) == NULL ) {
        OOFEM_ERROR("failed to allocate vsize");
    }

    for ( ie = 0, i = 0; i < nelem; i++ ) {
        ielem = domain->giveElement(i + 1);
        if ( ielem->giveParallelMode() == Element_local ) {
            vwgt [ ie ]    = ( int ) ( ielem->predictRelativeComputationalCost() * 100.0 );
            vsize [ ie++ ] = 1; //ielem->predictRelativeRedistributionCost();
        }
    }

    wgtflag = 2;
    numflag = 0;
    ncon = 1;
    if ( ( part = new idx_t [ nlocalelems ] ) == NULL ) {
        OOFEM_ERROR("failed to allocate part");
    }

    // call ParMETIS balancing routineParMETIS_V3_AdaptiveRepart
    ParMETIS_V3_AdaptiveRepart(elmdist, xadj, adjncy, vwgt, vsize, NULL, & wgtflag, & numflag, & ncon, & nproc,
                               tpwgts, ubvec, & itr, options, & edgecut, part, & communicator);

    // part contains partition vector for local elements on receiver
    // we need to map it to domain elements (this is not the same, since
    // domain may contain not only its local elements but remote elements as well)
    int loc_num = 0;
    this->elementPart.resize(nelem);
    for ( i = 1; i <= nelem; i++ ) {
        ielem = domain->giveElement(i);
        if ( ielem->giveParallelMode() == Element_local ) {
            this->elementPart.at(i) = part [ loc_num++ ];
        } else {
            // we can not say anything about remote elements; this information is available on partition
            // that has its local counterpart
            this->elementPart.at(i) = -1;
        }
    }

    if ( part ) {
        delete[] part;
    }

 #ifdef ParmetisLoadBalancer_DEBUG_PRINT
    // debug
    fprintf(stderr, "[%d] edgecut: %d elementPart:", myrank, edgecut);
    for ( i = 1; i <= nelem; i++ ) {
        fprintf( stderr, " %d", elementPart.at(i) );
    }

    fprintf(stderr, "\n");
 #endif

    // delete allocated xadj, adjncy arrays by ParMETIS
    delete[] eind;
    delete[] eptr;
    delete[] vwgt;
    delete[] vsize;
    free(xadj);
    free(adjncy);

    this->labelDofManagers();
}