/***************************************************************************** * This function creates a graph corresponding to the finite element mesh. * At this point the supported elements are triangles, tetrahedrons. ******************************************************************************/ void METIS_MeshToNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) { int esizes[] = {-1, 3, 4, 8, 4}; if (*numflag == 1) ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts); switch (*etype) { case 1: TRINODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); break; case 2: TETNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); break; case 3: HEXNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); break; case 4: QUADNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); break; } if (*numflag == 1) ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *nn, dxadj, dadjncy); }
/***************************************************************************** * This function creates a graph corresponding to the dual of a finite element * mesh. At this point the supported elements are triangles, tetrahedrons, and * bricks. ******************************************************************************/ void METIS_MeshToDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) { int esizes[] = {-1, 3, 4, 8, 4}; if (*numflag == 1) ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts); GENDUALMETIS(*ne, *nn, *etype, elmnts, dxadj, dadjncy); if (*numflag == 1) ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *ne, dxadj, dadjncy); }
int METIS_MeshToDual(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind, idx_t *ncommon, idx_t *numflag, idx_t **r_xadj, idx_t **r_adjncy) { int sigrval=0, renumber=0; /* set up malloc cleaning code and signal catchers */ if (!gk_malloc_init()) return METIS_ERROR_MEMORY; gk_sigtrap(); if ((sigrval = gk_sigcatch()) != 0) goto SIGTHROW; /* renumber the mesh */ if (*numflag == 1) { ChangeMesh2CNumbering(*ne, eptr, eind); renumber = 1; } /* create dual graph */ *r_xadj = *r_adjncy = NULL; CreateGraphDual(*ne, *nn, eptr, eind, *ncommon, r_xadj, r_adjncy); SIGTHROW: if (renumber) ChangeMesh2FNumbering(*ne, eptr, eind, *ne, *r_xadj, *r_adjncy); gk_siguntrap(); gk_malloc_cleanup(0); if (sigrval != 0) { if (*r_xadj != NULL) free(*r_xadj); if (*r_adjncy != NULL) free(*r_adjncy); *r_xadj = *r_adjncy = NULL; } return metis_rcode(sigrval); }
/************************************************************************* * This function partitions a finite element mesh by partitioning its dual * graph using KMETIS and then assigning nodes in a load balanced fashion. **************************************************************************/ int METIS_PartMeshDual(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind, idx_t *vwgt, idx_t *vsize, idx_t *ncommon, idx_t *nparts, real_t *tpwgts, idx_t *options, idx_t *objval, idx_t *epart, idx_t *npart) { int sigrval=0, renumber=0, ptype; idx_t i, j; idx_t *xadj=NULL, *adjncy=NULL, *nptr=NULL, *nind=NULL; idx_t ncon=1, pnumflag=0; int rstatus = METIS_OK; /* set up malloc cleaning code and signal catchers */ if (!gk_malloc_init()) return METIS_ERROR_MEMORY; gk_sigtrap(); if ((sigrval = gk_sigcatch()) != 0) goto SIGTHROW; renumber = GETOPTION(options, METIS_OPTION_NUMBERING, 0); ptype = GETOPTION(options, METIS_OPTION_PTYPE, METIS_PTYPE_KWAY); /* renumber the mesh */ if (renumber) { ChangeMesh2CNumbering(*ne, eptr, eind); options[METIS_OPTION_NUMBERING] = 0; } /* get the dual graph */ rstatus = METIS_MeshToDual(ne, nn, eptr, eind, ncommon, &pnumflag, &xadj, &adjncy); if (rstatus != METIS_OK) raise(SIGERR); /* partition the graph */ if (ptype == METIS_PTYPE_KWAY) rstatus = METIS_PartGraphKway(ne, &ncon, xadj, adjncy, vwgt, vsize, NULL, nparts, tpwgts, NULL, options, objval, epart); else rstatus = METIS_PartGraphRecursive(ne, &ncon, xadj, adjncy, vwgt, vsize, NULL, nparts, tpwgts, NULL, options, objval, epart); if (rstatus != METIS_OK) raise(SIGERR); /* construct the node-element list */ nptr = ismalloc(*nn+1, 0, "METIS_PartMeshDual: nptr"); nind = imalloc(eptr[*ne], "METIS_PartMeshDual: nind"); for (i=0; i<*ne; i++) { for (j=eptr[i]; j<eptr[i+1]; j++) nptr[eind[j]]++; } MAKECSR(i, *nn, nptr); for (i=0; i<*ne; i++) { for (j=eptr[i]; j<eptr[i+1]; j++) nind[nptr[eind[j]]++] = i; } SHIFTCSR(i, *nn, nptr); /* partition the other side of the mesh */ InduceRowPartFromColumnPart(*nn, nptr, nind, npart, epart, *nparts, tpwgts); gk_free((void **)&nptr, &nind, LTERM); SIGTHROW: if (renumber) { ChangeMesh2FNumbering2(*ne, *nn, eptr, eind, epart, npart); options[METIS_OPTION_NUMBERING] = 1; } METIS_Free(xadj); METIS_Free(adjncy); gk_siguntrap(); gk_malloc_cleanup(0); return metis_rcode(sigrval); }
/************************************************************************* * This function partitions a finite element mesh by partitioning its nodal * graph using KMETIS and then assigning elements in a load balanced fashion. **************************************************************************/ int METIS_PartMeshNodal(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind, idx_t *vwgt, idx_t *vsize, idx_t *nparts, real_t *tpwgts, idx_t *options, idx_t *objval, idx_t *epart, idx_t *npart) { int sigrval=0, renumber=0, ptype; idx_t *xadj=NULL, *adjncy=NULL; idx_t ncon=1, pnumflag=0; int rstatus=METIS_OK; /* set up malloc cleaning code and signal catchers */ if (!gk_malloc_init()) return METIS_ERROR_MEMORY; gk_sigtrap(); if ((sigrval = gk_sigcatch()) != 0) goto SIGTHROW; renumber = GETOPTION(options, METIS_OPTION_NUMBERING, 0); ptype = GETOPTION(options, METIS_OPTION_PTYPE, METIS_PTYPE_KWAY); /* renumber the mesh */ if (renumber) { ChangeMesh2CNumbering(*ne, eptr, eind); options[METIS_OPTION_NUMBERING] = 0; } /* get the nodal graph */ rstatus = METIS_MeshToNodal(ne, nn, eptr, eind, &pnumflag, &xadj, &adjncy); if (rstatus != METIS_OK) raise(SIGERR); /* partition the graph */ if (ptype == METIS_PTYPE_KWAY) rstatus = METIS_PartGraphKway(nn, &ncon, xadj, adjncy, vwgt, vsize, NULL, nparts, tpwgts, NULL, options, objval, npart); else rstatus = METIS_PartGraphRecursive(nn, &ncon, xadj, adjncy, vwgt, vsize, NULL, nparts, tpwgts, NULL, options, objval, npart); if (rstatus != METIS_OK) raise(SIGERR); /* partition the other side of the mesh */ InduceRowPartFromColumnPart(*ne, eptr, eind, epart, npart, *nparts, tpwgts); SIGTHROW: if (renumber) { ChangeMesh2FNumbering2(*ne, *nn, eptr, eind, epart, npart); options[METIS_OPTION_NUMBERING] = 1; } METIS_Free(xadj); METIS_Free(adjncy); gk_siguntrap(); gk_malloc_cleanup(0); return metis_rcode(sigrval); }
/************************************************************************* * This function partitions a finite element mesh by partitioning its nodal * graph using KMETIS and then assigning elements in a load balanced fashion. **************************************************************************/ void METIS_PartMeshNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) { int i, j, k, me; idxtype *xadj, *adjncy, *pwgts; int options[10], pnumflag=0, wgtflag=0; int nnbrs, nbrind[200], nbrwgt[200], maxpwgt; int esize, esizes[] = {-1, 3, 4, 8, 4}; esize = esizes[*etype]; if (*numflag == 1) ChangeMesh2CNumbering((*ne)*esize, elmnts); xadj = idxmalloc(*nn+1, "METIS_MESHPARTNODAL: xadj"); adjncy = idxmalloc(20*(*nn), "METIS_MESHPARTNODAL: adjncy"); METIS_MeshToNodal(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy); adjncy = realloc(adjncy, xadj[*nn]*sizeof(idxtype)); options[0] = 0; METIS_PartGraphKway(nn, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, npart); /* OK, now compute an element partition based on the nodal partition npart */ idxset(*ne, -1, epart); pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTNODAL: pwgts"); for (i=0; i<*ne; i++) { me = npart[elmnts[i*esize]]; for (j=1; j<esize; j++) { if (npart[elmnts[i*esize+j]] != me) break; } if (j == esize) { epart[i] = me; pwgts[me]++; } } maxpwgt = 1.03*(*ne)/(*nparts); for (i=0; i<*ne; i++) { if (epart[i] == -1) { /* Assign the boundary element */ nnbrs = 0; for (j=0; j<esize; j++) { me = npart[elmnts[i*esize+j]]; for (k=0; k<nnbrs; k++) { if (nbrind[k] == me) { nbrwgt[k]++; break; } } if (k == nnbrs) { nbrind[nnbrs] = me; nbrwgt[nnbrs++] = 1; } } /* Try to assign it first to the domain with most things in common */ j = iamax(nnbrs, nbrwgt); if (pwgts[nbrind[j]] < maxpwgt) { epart[i] = nbrind[j]; } else { /* If that fails, assign it to a light domain */ for (j=0; j<nnbrs; j++) { if (pwgts[nbrind[j]] < maxpwgt) { epart[i] = nbrind[j]; break; } } if (j == nnbrs) epart[i] = nbrind[iamax(nnbrs, nbrwgt)]; } pwgts[epart[i]]++; } } if (*numflag == 1) ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart); GKfree(&xadj, &adjncy, &pwgts, LTERM); }
void METIS_PartMeshDual_WV(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart, idxtype *vwgts) { int i, j, k, me; idxtype *xadj, *adjncy, *pwgts, *nptr, *nind; int options[10], pnumflag=0, wgtflag=2; int nnbrs, nbrind[200], nbrwgt[200], maxpwgt; int esize, esizes[] = {-1, 3, 4, 8, 4}; esize = esizes[*etype]; if (*numflag == 1) ChangeMesh2CNumbering((*ne)*esize, elmnts); xadj = idxmalloc(*ne+1, "METIS_MESHPARTNODAL: xadj"); adjncy = idxmalloc(esize*(*ne), "METIS_MESHPARTNODAL: adjncy"); METIS_MeshToDual(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy); options[0] = 0; METIS_PartGraphKway(ne, xadj, adjncy, vwgts, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, epart); /* Construct the node-element list */ nptr = idxsmalloc(*nn+1, 0, "METIS_MESHPARTDUAL: nptr"); for (j=esize*(*ne), i=0; i<j; i++) nptr[elmnts[i]]++; MAKECSR(i, *nn, nptr); nind = idxmalloc(nptr[*nn], "METIS_MESHPARTDUAL: nind"); for (k=i=0; i<(*ne); i++) { for (j=0; j<esize; j++, k++) nind[nptr[elmnts[k]]++] = i; } for (i=(*nn); i>0; i--) nptr[i] = nptr[i-1]; nptr[0] = 0; /* OK, now compute a nodal partition based on the element partition npart */ idxset(*nn, -1, npart); pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTDUAL: pwgts"); for (i=0; i<*nn; i++) { me = epart[nind[nptr[i]]]; for (j=nptr[i]+1; j<nptr[i+1]; j++) { if (epart[nind[j]] != me) break; } if (j == nptr[i+1]) { npart[i] = me; pwgts[me]++; } } maxpwgt = 1.03*(*nn)/(*nparts); for (i=0; i<*nn; i++) { if (npart[i] == -1) { /* Assign the boundary element */ nnbrs = 0; for (j=nptr[i]; j<nptr[i+1]; j++) { me = epart[nind[j]]; for (k=0; k<nnbrs; k++) { if (nbrind[k] == me) { nbrwgt[k]++; break; } } if (k == nnbrs) { nbrind[nnbrs] = me; nbrwgt[nnbrs++] = 1; } } /* Try to assign it first to the domain with most things in common */ j = iamax(nnbrs, nbrwgt); if (pwgts[nbrind[j]] < maxpwgt) { npart[i] = nbrind[j]; } else { /* If that fails, assign it to a light domain */ npart[i] = nbrind[0]; for (j=0; j<nnbrs; j++) { if (pwgts[nbrind[j]] < maxpwgt) { npart[i] = nbrind[j]; break; } } } pwgts[npart[i]]++; } } if (*numflag == 1) ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart); GKfree(&xadj, &adjncy, &pwgts, &nptr, &nind, LTERM); }