Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/meshpart.c
3206 views
/*1* Copyright 1997, Regents of the University of Minnesota2*3* meshpart.c4*5* This file contains routines for partitioning finite element meshes.6*7* Started 9/29/978* George9*10* $Id: meshpart.c 13931 2013-03-29 16:48:48Z karypis $11*12*/1314#include "metislib.h"151617/*************************************************************************18* This function partitions a finite element mesh by partitioning its nodal19* graph using KMETIS and then assigning elements in a load balanced fashion.20**************************************************************************/21int METIS_PartMeshNodal(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind,22idx_t *vwgt, idx_t *vsize, idx_t *nparts, real_t *tpwgts,23idx_t *options, idx_t *objval, idx_t *epart, idx_t *npart)24{25int sigrval=0, renumber=0, ptype;26idx_t *xadj=NULL, *adjncy=NULL;27idx_t ncon=1, pnumflag=0;28int rstatus=METIS_OK;2930/* set up malloc cleaning code and signal catchers */31if (!gk_malloc_init())32return METIS_ERROR_MEMORY;3334gk_sigtrap();3536if ((sigrval = gk_sigcatch()) != 0)37goto SIGTHROW;3839renumber = GETOPTION(options, METIS_OPTION_NUMBERING, 0);40ptype = GETOPTION(options, METIS_OPTION_PTYPE, METIS_PTYPE_KWAY);4142/* renumber the mesh */43if (renumber) {44ChangeMesh2CNumbering(*ne, eptr, eind);45options[METIS_OPTION_NUMBERING] = 0;46}4748/* get the nodal graph */49rstatus = METIS_MeshToNodal(ne, nn, eptr, eind, &pnumflag, &xadj, &adjncy);50if (rstatus != METIS_OK)51raise(SIGERR);5253/* partition the graph */54if (ptype == METIS_PTYPE_KWAY)55rstatus = METIS_PartGraphKway(nn, &ncon, xadj, adjncy, vwgt, vsize, NULL,56nparts, tpwgts, NULL, options, objval, npart);57else58rstatus = METIS_PartGraphRecursive(nn, &ncon, xadj, adjncy, vwgt, vsize, NULL,59nparts, tpwgts, NULL, options, objval, npart);6061if (rstatus != METIS_OK)62raise(SIGERR);6364/* partition the other side of the mesh */65InduceRowPartFromColumnPart(*ne, eptr, eind, epart, npart, *nparts, tpwgts);666768SIGTHROW:69if (renumber) {70ChangeMesh2FNumbering2(*ne, *nn, eptr, eind, epart, npart);71options[METIS_OPTION_NUMBERING] = 1;72}7374METIS_Free(xadj);75METIS_Free(adjncy);7677gk_siguntrap();78gk_malloc_cleanup(0);7980return metis_rcode(sigrval);81}82838485/*************************************************************************86* This function partitions a finite element mesh by partitioning its dual87* graph using KMETIS and then assigning nodes in a load balanced fashion.88**************************************************************************/89int METIS_PartMeshDual(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind,90idx_t *vwgt, idx_t *vsize, idx_t *ncommon, idx_t *nparts,91real_t *tpwgts, idx_t *options, idx_t *objval, idx_t *epart,92idx_t *npart)93{94int sigrval=0, renumber=0, ptype;95idx_t i, j;96idx_t *xadj=NULL, *adjncy=NULL, *nptr=NULL, *nind=NULL;97idx_t ncon=1, pnumflag=0;98int rstatus = METIS_OK;99100/* set up malloc cleaning code and signal catchers */101if (!gk_malloc_init())102return METIS_ERROR_MEMORY;103104gk_sigtrap();105106if ((sigrval = gk_sigcatch()) != 0)107goto SIGTHROW;108109renumber = GETOPTION(options, METIS_OPTION_NUMBERING, 0);110ptype = GETOPTION(options, METIS_OPTION_PTYPE, METIS_PTYPE_KWAY);111112/* renumber the mesh */113if (renumber) {114ChangeMesh2CNumbering(*ne, eptr, eind);115options[METIS_OPTION_NUMBERING] = 0;116}117118/* get the dual graph */119rstatus = METIS_MeshToDual(ne, nn, eptr, eind, ncommon, &pnumflag, &xadj, &adjncy);120if (rstatus != METIS_OK)121raise(SIGERR);122123/* partition the graph */124if (ptype == METIS_PTYPE_KWAY)125rstatus = METIS_PartGraphKway(ne, &ncon, xadj, adjncy, vwgt, vsize, NULL,126nparts, tpwgts, NULL, options, objval, epart);127else128rstatus = METIS_PartGraphRecursive(ne, &ncon, xadj, adjncy, vwgt, vsize, NULL,129nparts, tpwgts, NULL, options, objval, epart);130131if (rstatus != METIS_OK)132raise(SIGERR);133134135/* construct the node-element list */136nptr = ismalloc(*nn+1, 0, "METIS_PartMeshDual: nptr");137nind = imalloc(eptr[*ne], "METIS_PartMeshDual: nind");138139for (i=0; i<*ne; i++) {140for (j=eptr[i]; j<eptr[i+1]; j++)141nptr[eind[j]]++;142}143MAKECSR(i, *nn, nptr);144145for (i=0; i<*ne; i++) {146for (j=eptr[i]; j<eptr[i+1]; j++)147nind[nptr[eind[j]]++] = i;148}149SHIFTCSR(i, *nn, nptr);150151/* partition the other side of the mesh */152InduceRowPartFromColumnPart(*nn, nptr, nind, npart, epart, *nparts, tpwgts);153154gk_free((void **)&nptr, &nind, LTERM);155156157SIGTHROW:158if (renumber) {159ChangeMesh2FNumbering2(*ne, *nn, eptr, eind, epart, npart);160options[METIS_OPTION_NUMBERING] = 1;161}162163METIS_Free(xadj);164METIS_Free(adjncy);165166gk_siguntrap();167gk_malloc_cleanup(0);168169return metis_rcode(sigrval);170}171172173174/*************************************************************************/175/*! Induces a partitioning of the rows based on a a partitioning of the176columns. It is used by both the Nodal and Dual routines. */177/*************************************************************************/178void InduceRowPartFromColumnPart(idx_t nrows, idx_t *rowptr, idx_t *rowind,179idx_t *rpart, idx_t *cpart, idx_t nparts, real_t *tpwgts)180{181idx_t i, j, k, me;182idx_t nnbrs, *pwgts, *nbrdom, *nbrwgt, *nbrmrk;183idx_t *itpwgts;184185pwgts = ismalloc(nparts, 0, "InduceRowPartFromColumnPart: pwgts");186nbrdom = ismalloc(nparts, 0, "InduceRowPartFromColumnPart: nbrdom");187nbrwgt = ismalloc(nparts, 0, "InduceRowPartFromColumnPart: nbrwgt");188nbrmrk = ismalloc(nparts, -1, "InduceRowPartFromColumnPart: nbrmrk");189190iset(nrows, -1, rpart);191192/* setup the integer target partition weights */193itpwgts = imalloc(nparts, "InduceRowPartFromColumnPart: itpwgts");194if (tpwgts == NULL) {195iset(nparts, 1+nrows/nparts, itpwgts);196}197else {198for (i=0; i<nparts; i++)199itpwgts[i] = 1+nrows*tpwgts[i];200}201202/* first assign the rows consisting only of columns that belong to203a single partition. Assign rows that are empty to -2 (un-assigned) */204for (i=0; i<nrows; i++) {205if (rowptr[i+1]-rowptr[i] == 0) {206rpart[i] = -2;207continue;208}209210me = cpart[rowind[rowptr[i]]];211for (j=rowptr[i]+1; j<rowptr[i+1]; j++) {212if (cpart[rowind[j]] != me)213break;214}215if (j == rowptr[i+1]) {216rpart[i] = me;217pwgts[me]++;218}219}220221/* next assign the rows consisting of columns belonging to multiple222partitions in a balanced way */223for (i=0; i<nrows; i++) {224if (rpart[i] == -1) {225for (nnbrs=0, j=rowptr[i]; j<rowptr[i+1]; j++) {226me = cpart[rowind[j]];227if (nbrmrk[me] == -1) {228nbrdom[nnbrs] = me;229nbrwgt[nnbrs] = 1;230nbrmrk[me] = nnbrs++;231}232else {233nbrwgt[nbrmrk[me]]++;234}235}236ASSERT(nnbrs > 0);237238/* assign it first to the domain with most things in common */239rpart[i] = nbrdom[iargmax(nnbrs, nbrwgt)];240241/* if overweight, assign it to the light domain */242if (pwgts[rpart[i]] > itpwgts[rpart[i]]) {243for (j=0; j<nnbrs; j++) {244if (pwgts[nbrdom[j]] < itpwgts[nbrdom[j]] ||245pwgts[nbrdom[j]]-itpwgts[nbrdom[j]] < pwgts[rpart[i]]-itpwgts[rpart[i]]) {246rpart[i] = nbrdom[j];247break;248}249}250}251pwgts[rpart[i]]++;252253/* reset nbrmrk array */254for (j=0; j<nnbrs; j++)255nbrmrk[nbrdom[j]] = -1;256}257}258259gk_free((void **)&pwgts, &nbrdom, &nbrwgt, &nbrmrk, &itpwgts, LTERM);260261}262263264