/*********************************************************************************** * * This function is the entry point of the parallel k-way multilevel partitionioner. * * This function assumes nothing about the graph distribution. * * It is the general case. * ************************************************************************************/ void PARKMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt, idxtype *part, int *options, MPI_Comm comm) { int wgtflag, numflag, edgecut, newoptions[5]; int npes; MPI_Comm_size(comm, &npes); newoptions[0] = 1; newoptions[OPTION_IPART] = options[2]; newoptions[OPTION_FOLDF] = options[1]; newoptions[OPTION_DBGLVL] = options[4]; numflag = options[3]; wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1); ParMETIS_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &npes, newoptions, &edgecut, part, &comm); options[0] = edgecut; }
// same as above, but assumes that the matrix A has symmetric sparsity pattern. Only recommended for use // on a matrix that has been formed directly from a finite volume mesh. void mtx_CRS_dist_domdec_sym( Tmtx_CRS_dist_ptr A, Tdistribution_ptr dist, int *p ) { int i, n_nodes, dom, count, n_dom, pos, edgecut, numflag=0, wgtflag=0, this_dom, n_neigh=0; int *vstarts=NULL, *indx=NULL, *starts=NULL, *counts=NULL, *part=NULL, *ppart=NULL, *_cindx=NULL, *_rindx=NULL; int ParMETIS_options[4] = {0, 0, 0, 0}; TMPI_dat_ptr This=NULL; This = &A->This; // initialise variables n_nodes = A->mtx.nrows; n_dom = This->n_proc; this_dom = This->this_proc; // initialise the distribution distribution_init( dist, n_dom, n_nodes, 1 ); // setup pointers indx = dist->indx; starts = dist->starts; counts = dist->counts; part = dist->part; ppart = dist->ppart; // make the CRS profile of the matrix into an adjacency graph _cindx = malloc( (A->mtx.nnz)*sizeof(int) ); _rindx = malloc( (n_nodes+1)*sizeof(int) ); index_make_adjacency( n_nodes, A->vtxdist[this_dom], A->mtx.cindx, A->mtx.rindx, _cindx, _rindx ); // use ParMETIS to perform domain decomp ParMETIS_PartKway( A->vtxdist, _rindx, _cindx, NULL, NULL, &wgtflag, &numflag, &n_dom, ParMETIS_options, &edgecut, part, &This->comm); // keep copy of original part in ppart memcpy( ppart, part, sizeof(int)*n_nodes ); // sort part, indx holds the permutation required for This for( i=0; i<n_nodes; i++ ) indx[i]=i; heapsort_int_index( n_nodes, indx, part); // determine the number of nodes that we have for each processor pos = 0; for( dom=0; dom<n_dom; dom++ ) { starts[dom] = pos; count=0; while( part[pos]==dom && pos<A->mtx.nrows ) { pos++; count++; } counts[dom] = count; if( count ) n_neigh++; } starts[dom] = pos; // find and store the neighbour information to dist free( dist->neighbours ); dist->neighbours = (int *)malloc( sizeof(int)*n_neigh ); dist->n_neigh = n_neigh; for( pos=0, dom=0; dom<n_dom; dom++ ) if( counts[dom] ) dist->neighbours[pos++] = dom; // sort the indices of each target domain's nodes for( dom=0; dom<n_dom; dom++ ) if( counts[dom]>1 ) heapsort_int( counts[dom], indx + starts[dom] ); // all processes update their copy of the global partition vector in p vstarts = (int *)malloc( sizeof(int)*n_dom ); for( i=0; i<n_dom; i++ ) vstarts[i] = A->vtxdist[i+1] - A->vtxdist[i]; MPI_Allgatherv( ppart, vstarts[this_dom], MPI_INT, p, vstarts, A->vtxdist, MPI_INT, This->comm ); free( vstarts ); free( _rindx ); free( _cindx ); }