mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
321 lines
11 KiB
C
321 lines
11 KiB
C
/*
|
|
* Copyright 1997, Regents of the University of Minnesota
|
|
*
|
|
* mmatch.c
|
|
*
|
|
* This file contains code that finds a matching
|
|
*
|
|
* Started 2/22/96
|
|
* George
|
|
*
|
|
* $Id: match.c,v 1.2 2003/07/21 17:18:50 karypis Exp $
|
|
*
|
|
*/
|
|
|
|
#include <parmetislib.h>
|
|
|
|
|
|
/*************************************************************************
|
|
* This function finds a matching
|
|
**************************************************************************/
|
|
void Moc_GlobalMatch_Balance(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
|
|
{
|
|
int h, i, ii, j, k;
|
|
int nnbrs, nvtxs, ncon, cnvtxs, firstvtx, lastvtx, maxi, maxidx, nkept;
|
|
int otherlastvtx, nrequests, nchanged, pass, nmatched, wside;
|
|
idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *home, *myhome, *shome, *rhome;
|
|
idxtype *match, *rmatch, *smatch;
|
|
idxtype *peind, *sendptr, *recvptr;
|
|
idxtype *perm, *iperm, *nperm, *changed;
|
|
float *nvwgt, maxnvwgt;
|
|
int *nreqs_pe;
|
|
KeyValueType *match_requests, *match_granted, *pe_requests;
|
|
|
|
maxnvwgt = 1.0/((float)(ctrl->nparts)*MAXNVWGT_FACTOR);
|
|
|
|
graph->match_type = MATCH_GLOBAL;
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
|
|
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
|
|
|
|
nvtxs = graph->nvtxs;
|
|
ncon = graph->ncon;
|
|
xadj = graph->xadj;
|
|
ladjncy = graph->adjncy;
|
|
adjwgt = graph->adjwgt;
|
|
home = graph->home;
|
|
nvwgt = graph->nvwgt;
|
|
|
|
vtxdist = graph->vtxdist;
|
|
firstvtx = vtxdist[ctrl->mype];
|
|
lastvtx = vtxdist[ctrl->mype+1];
|
|
|
|
match = graph->match = idxsmalloc(nvtxs+graph->nrecv, UNMATCHED, "HEM_Match: match");
|
|
myhome = idxsmalloc(nvtxs+graph->nrecv, UNMATCHED, "HEM_Match: myhome");
|
|
|
|
/*------------------------------------------------------------
|
|
/ Send/Receive the home information of interface vertices
|
|
/------------------------------------------------------------*/
|
|
if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
|
|
idxcopy(nvtxs, home, myhome);
|
|
shome = wspace->indices;
|
|
rhome = myhome + nvtxs;
|
|
CommInterfaceData(ctrl, graph, myhome, shome, rhome);
|
|
}
|
|
|
|
nnbrs = graph->nnbrs;
|
|
peind = graph->peind;
|
|
sendptr = graph->sendptr;
|
|
recvptr = graph->recvptr;
|
|
|
|
/* Use wspace->indices as the tmp space for matching info of the boundary
|
|
* vertices that are sent and received */
|
|
rmatch = match + nvtxs;
|
|
smatch = wspace->indices;
|
|
changed = smatch+graph->nsend;
|
|
|
|
/* Use wspace->indices as the tmp space for match requests of the boundary
|
|
* vertices that are sent and received */
|
|
match_requests = wspace->pairs;
|
|
match_granted = match_requests + graph->nsend;
|
|
|
|
nreqs_pe = ismalloc(nnbrs, 0, "Match_HEM: nreqs_pe");
|
|
|
|
nkept = graph->gnvtxs/ctrl->npes - nvtxs;
|
|
|
|
perm = (idxtype *)wspace->degrees;
|
|
iperm = perm + nvtxs;
|
|
FastRandomPermute(nvtxs, perm, 1);
|
|
for (i=0; i<nvtxs; i++)
|
|
iperm[perm[i]] = i;
|
|
|
|
nperm = iperm + nvtxs;
|
|
for (i=0; i<nnbrs; i++)
|
|
nperm[i] = i;
|
|
|
|
/*************************************************************
|
|
* Go now and find a matching by doing multiple iterations
|
|
*************************************************************/
|
|
/* First nullify the heavy vertices */
|
|
for (nchanged=i=0; i<nvtxs; i++) {
|
|
for (h=0; h<ncon; h++)
|
|
if (nvwgt[i*ncon+h] > maxnvwgt) {
|
|
break;
|
|
}
|
|
|
|
if (h != ncon) {
|
|
match[i] = TOO_HEAVY;
|
|
nchanged++;
|
|
}
|
|
}
|
|
if (GlobalSESum(ctrl, nchanged) > 0) {
|
|
IFSET(ctrl->dbglvl, DBG_PROGRESS,
|
|
rprintf(ctrl, "We found %d heavy vertices!\n", GlobalSESum(ctrl, nchanged)));
|
|
CommInterfaceData(ctrl, graph, match, smatch, rmatch);
|
|
}
|
|
|
|
|
|
for (nmatched=pass=0; pass<NMATCH_PASSES; pass++) {
|
|
wside = (graph->level+pass)%2;
|
|
nchanged = nrequests = 0;
|
|
for (ii=nmatched; ii<nvtxs; ii++) {
|
|
i = perm[ii];
|
|
if (match[i] == UNMATCHED) { /* Unmatched */
|
|
maxidx = i;
|
|
maxi = -1;
|
|
|
|
/* Find a heavy-edge matching */
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
k = ladjncy[j];
|
|
if (match[k] == UNMATCHED &&
|
|
myhome[k] == myhome[i] &&
|
|
(maxi == -1 ||
|
|
adjwgt[maxi] < adjwgt[j] ||
|
|
(maxidx < nvtxs &&
|
|
k < nvtxs &&
|
|
adjwgt[maxi] == adjwgt[j] &&
|
|
BetterVBalance(ncon,nvwgt+i*ncon,nvwgt+maxidx*ncon,nvwgt+k*ncon) >= 0))) {
|
|
maxi = j;
|
|
maxidx = k;
|
|
}
|
|
}
|
|
|
|
if (maxi != -1) {
|
|
k = ladjncy[maxi];
|
|
if (k < nvtxs) { /* Take care the local vertices first */
|
|
/* Here we give preference the local matching by granting it right away */
|
|
if (i <= k) {
|
|
match[i] = firstvtx+k + KEEP_BIT;
|
|
match[k] = firstvtx+i;
|
|
}
|
|
else {
|
|
match[i] = firstvtx+k;
|
|
match[k] = firstvtx+i + KEEP_BIT;
|
|
}
|
|
changed[nchanged++] = i;
|
|
changed[nchanged++] = k;
|
|
}
|
|
else { /* Take care any remote boundary vertices */
|
|
match[k] = MAYBE_MATCHED;
|
|
/* Alternate among which vertices will issue the requests */
|
|
if ((wside ==0 && firstvtx+i < graph->imap[k]) || (wside == 1 && firstvtx+i > graph->imap[k])) {
|
|
match[i] = MAYBE_MATCHED;
|
|
match_requests[nrequests].key = graph->imap[k];
|
|
match_requests[nrequests].val = firstvtx+i;
|
|
nrequests++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_MATCH
|
|
PrintVector2(ctrl, nvtxs, firstvtx, match, "Match1");
|
|
myprintf(ctrl, "[c: %2d] Nlocal: %d, Nrequests: %d\n", c, nlocal, nrequests);
|
|
#endif
|
|
|
|
|
|
/***********************************************************
|
|
* Exchange the match_requests, requests for me are stored in
|
|
* match_granted
|
|
************************************************************/
|
|
/* Issue the receives first. Note that from each PE can receive a maximum
|
|
of the interface node that it needs to send it in the case of a mat-vec */
|
|
for (i=0; i<nnbrs; i++) {
|
|
MPI_Irecv((void *)(match_granted+recvptr[i]), 2*(recvptr[i+1]-recvptr[i]), IDX_DATATYPE,
|
|
peind[i], 1, ctrl->comm, ctrl->rreq+i);
|
|
}
|
|
|
|
/* Issue the sends next. This needs some work */
|
|
ikeysort(nrequests, match_requests);
|
|
for (j=i=0; i<nnbrs; i++) {
|
|
otherlastvtx = vtxdist[peind[i]+1];
|
|
for (k=j; k<nrequests && match_requests[k].key < otherlastvtx; k++);
|
|
MPI_Isend((void *)(match_requests+j), 2*(k-j), IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
|
|
j = k;
|
|
}
|
|
|
|
/* OK, now get into the loop waiting for the operations to finish */
|
|
MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
|
|
for (i=0; i<nnbrs; i++) {
|
|
MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nreqs_pe+i);
|
|
nreqs_pe[i] = nreqs_pe[i]/2; /* Adjust for pairs of IDX_DATATYPE */
|
|
}
|
|
MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
|
|
|
|
|
|
/***********************************************************
|
|
* Now, go and service the requests that you received in
|
|
* match_granted
|
|
************************************************************/
|
|
RandomPermute(nnbrs, nperm, 0);
|
|
for (ii=0; ii<nnbrs; ii++) {
|
|
i = nperm[ii];
|
|
pe_requests = match_granted+recvptr[i];
|
|
for (j=0; j<nreqs_pe[i]; j++) {
|
|
k = pe_requests[j].key;
|
|
ASSERTP(ctrl, k >= firstvtx && k < lastvtx, (ctrl, "%d %d %d %d %d\n", firstvtx, lastvtx, k, j, peind[i]));
|
|
/* myprintf(ctrl, "Requesting a match %d %d\n", pe_requests[j].key, pe_requests[j].val); */
|
|
if (match[k-firstvtx] == UNMATCHED) { /* Bingo, lets grant this request */
|
|
changed[nchanged++] = k-firstvtx;
|
|
if (nkept >= 0) { /* Flip a coin for who gets it */
|
|
match[k-firstvtx] = pe_requests[j].val + KEEP_BIT;
|
|
nkept--;
|
|
}
|
|
else {
|
|
match[k-firstvtx] = pe_requests[j].val;
|
|
pe_requests[j].key += KEEP_BIT;
|
|
nkept++;
|
|
}
|
|
/* myprintf(ctrl, "Request from pe:%d (%d %d) granted!\n", peind[i], pe_requests[j].val, pe_requests[j].key); */
|
|
}
|
|
else { /* We are not granting the request */
|
|
/* myprintf(ctrl, "Request from pe:%d (%d %d) not granted!\n", peind[i], pe_requests[j].val, pe_requests[j].key); */
|
|
pe_requests[j].key = UNMATCHED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************
|
|
* Exchange the match_granted information. It is stored in
|
|
* match_requests
|
|
************************************************************/
|
|
/* Issue the receives first. Note that from each PE can receive a maximum
|
|
of the interface node that it needs to send during the case of a mat-vec */
|
|
for (i=0; i<nnbrs; i++) {
|
|
MPI_Irecv((void *)(match_requests+sendptr[i]), 2*(sendptr[i+1]-sendptr[i]), IDX_DATATYPE,
|
|
peind[i], 1, ctrl->comm, ctrl->rreq+i);
|
|
}
|
|
|
|
/* Issue the sends next. */
|
|
for (i=0; i<nnbrs; i++) {
|
|
MPI_Isend((void *)(match_granted+recvptr[i]), 2*nreqs_pe[i], IDX_DATATYPE,
|
|
peind[i], 1, ctrl->comm, ctrl->sreq+i);
|
|
}
|
|
|
|
/* OK, now get into the loop waiting for the operations to finish */
|
|
MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
|
|
for (i=0; i<nnbrs; i++) {
|
|
MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nreqs_pe+i);
|
|
nreqs_pe[i] = nreqs_pe[i]/2; /* Adjust for pairs of IDX_DATATYPE */
|
|
}
|
|
MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
|
|
|
|
|
|
/***********************************************************
|
|
* Now, go and through the match_requests and update local
|
|
* match information for the matchings that were granted.
|
|
************************************************************/
|
|
for (i=0; i<nnbrs; i++) {
|
|
pe_requests = match_requests+sendptr[i];
|
|
for (j=0; j<nreqs_pe[i]; j++) {
|
|
match[pe_requests[j].val-firstvtx] = pe_requests[j].key;
|
|
if (pe_requests[j].key != UNMATCHED)
|
|
changed[nchanged++] = pe_requests[j].val-firstvtx;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<nchanged; i++) {
|
|
ii = iperm[changed[i]];
|
|
perm[ii] = perm[nmatched];
|
|
iperm[perm[nmatched]] = ii;
|
|
nmatched++;
|
|
}
|
|
|
|
CommChangedInterfaceData(ctrl, graph, nchanged, changed, match, match_requests, match_granted, wspace->pv4);
|
|
}
|
|
|
|
/* Traverse the vertices and those that were unmatched, match them with themselves */
|
|
cnvtxs = 0;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (match[i] == UNMATCHED || match[i] == TOO_HEAVY) {
|
|
match[i] = (firstvtx+i) + KEEP_BIT;
|
|
cnvtxs++;
|
|
}
|
|
else if (match[i] >= KEEP_BIT) { /* A matched vertex which I get to keep */
|
|
cnvtxs++;
|
|
}
|
|
}
|
|
|
|
if (ctrl->dbglvl&DBG_MATCHINFO) {
|
|
PrintVector2(ctrl, nvtxs, firstvtx, match, "Match");
|
|
myprintf(ctrl, "Cnvtxs: %d\n", cnvtxs);
|
|
rprintf(ctrl, "Done with matching...\n");
|
|
}
|
|
|
|
GKfree((void **)(&myhome), (void **)(&nreqs_pe), LTERM);
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
|
|
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
|
|
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
|
|
|
|
Moc_Global_CreateCoarseGraph(ctrl, graph, wspace, cnvtxs);
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
|
|
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
|
|
|
|
}
|
|
|