Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/mesh.c
3206 views
/*1* Copyright 1997, Regents of the University of Minnesota2*3* mesh.c4*5* This file contains routines for converting 3D and 4D finite element6* meshes into dual or nodal graphs7*8* Started 8/18/979* George10*11* $Id: mesh.c 13804 2013-03-04 23:49:08Z karypis $12*13*/1415#include "metislib.h"161718/*****************************************************************************/19/*! This function creates a graph corresponding to the dual of a finite element20mesh.2122\param ne is the number of elements in the mesh.23\param nn is the number of nodes in the mesh.24\param eptr is an array of size ne+1 used to mark the start and end25locations in the nind array.26\param eind is an array that stores for each element the set of node IDs27(indices) that it is made off. The length of this array is equal28to the total number of nodes over all the mesh elements.29\param ncommon is the minimum number of nodes that two elements must share30in order to be connected via an edge in the dual graph.31\param numflag is either 0 or 1 indicating if the numbering of the nodes32starts from 0 or 1, respectively. The same numbering is used for the33returned graph as well.34\param r_xadj indicates where the adjacency list of each vertex is stored35in r_adjncy. The memory for this array is allocated by this routine.36It can be freed by calling METIS_free().37\param r_adjncy stores the adjacency list of each vertex in the generated38dual graph. The memory for this array is allocated by this routine.39It can be freed by calling METIS_free().4041*/42/*****************************************************************************/43int METIS_MeshToDual(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind,44idx_t *ncommon, idx_t *numflag, idx_t **r_xadj, idx_t **r_adjncy)45{46int sigrval=0, renumber=0;4748/* set up malloc cleaning code and signal catchers */49if (!gk_malloc_init())50return METIS_ERROR_MEMORY;5152gk_sigtrap();5354if ((sigrval = gk_sigcatch()) != 0)55goto SIGTHROW;565758/* renumber the mesh */59if (*numflag == 1) {60ChangeMesh2CNumbering(*ne, eptr, eind);61renumber = 1;62}6364/* create dual graph */65*r_xadj = *r_adjncy = NULL;66CreateGraphDual(*ne, *nn, eptr, eind, *ncommon, r_xadj, r_adjncy);676869SIGTHROW:70if (renumber)71ChangeMesh2FNumbering(*ne, eptr, eind, *ne, *r_xadj, *r_adjncy);7273gk_siguntrap();74gk_malloc_cleanup(0);7576if (sigrval != 0) {77if (*r_xadj != NULL)78free(*r_xadj);79if (*r_adjncy != NULL)80free(*r_adjncy);81*r_xadj = *r_adjncy = NULL;82}8384return metis_rcode(sigrval);85}868788/*****************************************************************************/89/*! This function creates a graph corresponding to (almost) the nodal of a90finite element mesh. In the nodal graph, each node is connected to the91nodes corresponding to the union of nodes present in all the elements92in which that node belongs.9394\param ne is the number of elements in the mesh.95\param nn is the number of nodes in the mesh.96\param eptr is an array of size ne+1 used to mark the start and end97locations in the nind array.98\param eind is an array that stores for each element the set of node IDs99(indices) that it is made off. The length of this array is equal100to the total number of nodes over all the mesh elements.101\param numflag is either 0 or 1 indicating if the numbering of the nodes102starts from 0 or 1, respectively. The same numbering is used for the103returned graph as well.104\param r_xadj indicates where the adjacency list of each vertex is stored105in r_adjncy. The memory for this array is allocated by this routine.106It can be freed by calling METIS_free().107\param r_adjncy stores the adjacency list of each vertex in the generated108dual graph. The memory for this array is allocated by this routine.109It can be freed by calling METIS_free().110111*/112/*****************************************************************************/113int METIS_MeshToNodal(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind,114idx_t *numflag, idx_t **r_xadj, idx_t **r_adjncy)115{116int sigrval=0, renumber=0;117118/* set up malloc cleaning code and signal catchers */119if (!gk_malloc_init())120return METIS_ERROR_MEMORY;121122gk_sigtrap();123124if ((sigrval = gk_sigcatch()) != 0)125goto SIGTHROW;126127128/* renumber the mesh */129if (*numflag == 1) {130ChangeMesh2CNumbering(*ne, eptr, eind);131renumber = 1;132}133134/* create nodal graph */135*r_xadj = *r_adjncy = NULL;136CreateGraphNodal(*ne, *nn, eptr, eind, r_xadj, r_adjncy);137138139SIGTHROW:140if (renumber)141ChangeMesh2FNumbering(*ne, eptr, eind, *nn, *r_xadj, *r_adjncy);142143gk_siguntrap();144gk_malloc_cleanup(0);145146if (sigrval != 0) {147if (*r_xadj != NULL)148free(*r_xadj);149if (*r_adjncy != NULL)150free(*r_adjncy);151*r_xadj = *r_adjncy = NULL;152}153154return metis_rcode(sigrval);155}156157158/*****************************************************************************/159/*! This function creates the dual of a finite element mesh */160/*****************************************************************************/161void CreateGraphDual(idx_t ne, idx_t nn, idx_t *eptr, idx_t *eind, idx_t ncommon,162idx_t **r_xadj, idx_t **r_adjncy)163{164idx_t i, j, nnbrs;165idx_t *nptr, *nind;166idx_t *xadj, *adjncy;167idx_t *marker, *nbrs;168169if (ncommon < 1) {170printf(" Increased ncommon to 1, as it was initially %"PRIDX"\n", ncommon);171ncommon = 1;172}173174/* construct the node-element list first */175nptr = ismalloc(nn+1, 0, "CreateGraphDual: nptr");176nind = imalloc(eptr[ne], "CreateGraphDual: nind");177178for (i=0; i<ne; i++) {179for (j=eptr[i]; j<eptr[i+1]; j++)180nptr[eind[j]]++;181}182MAKECSR(i, nn, nptr);183184for (i=0; i<ne; i++) {185for (j=eptr[i]; j<eptr[i+1]; j++)186nind[nptr[eind[j]]++] = i;187}188SHIFTCSR(i, nn, nptr);189190191/* Allocate memory for xadj, since you know its size.192These are done using standard malloc as they are returned193to the calling function */194if ((xadj = (idx_t *)malloc((ne+1)*sizeof(idx_t))) == NULL)195gk_errexit(SIGMEM, "***Failed to allocate memory for xadj.\n");196*r_xadj = xadj;197iset(ne+1, 0, xadj);198199/* allocate memory for working arrays used by FindCommonElements */200marker = ismalloc(ne, 0, "CreateGraphDual: marker");201nbrs = imalloc(ne, "CreateGraphDual: nbrs");202203for (i=0; i<ne; i++) {204xadj[i] = FindCommonElements(i, eptr[i+1]-eptr[i], eind+eptr[i], nptr,205nind, eptr, ncommon, marker, nbrs);206}207MAKECSR(i, ne, xadj);208209/* Allocate memory for adjncy, since you now know its size.210These are done using standard malloc as they are returned211to the calling function */212if ((adjncy = (idx_t *)malloc(xadj[ne]*sizeof(idx_t))) == NULL) {213free(xadj);214*r_xadj = NULL;215gk_errexit(SIGMEM, "***Failed to allocate memory for adjncy.\n");216}217*r_adjncy = adjncy;218219for (i=0; i<ne; i++) {220nnbrs = FindCommonElements(i, eptr[i+1]-eptr[i], eind+eptr[i], nptr,221nind, eptr, ncommon, marker, nbrs);222for (j=0; j<nnbrs; j++)223adjncy[xadj[i]++] = nbrs[j];224}225SHIFTCSR(i, ne, xadj);226227gk_free((void **)&nptr, &nind, &marker, &nbrs, LTERM);228}229230231/*****************************************************************************/232/*! This function finds all elements that share at least ncommon nodes with233the ``query'' element.234*/235/*****************************************************************************/236idx_t FindCommonElements(idx_t qid, idx_t elen, idx_t *eind, idx_t *nptr,237idx_t *nind, idx_t *eptr, idx_t ncommon, idx_t *marker, idx_t *nbrs)238{239idx_t i, ii, j, jj, k, l, overlap;240241/* find all elements that share at least one node with qid */242for (k=0, i=0; i<elen; i++) {243j = eind[i];244for (ii=nptr[j]; ii<nptr[j+1]; ii++) {245jj = nind[ii];246247if (marker[jj] == 0)248nbrs[k++] = jj;249marker[jj]++;250}251}252253/* put qid into the neighbor list (in case it is not there) so that it254will be removed in the next step */255if (marker[qid] == 0)256nbrs[k++] = qid;257marker[qid] = 0;258259/* compact the list to contain only those with at least ncommon nodes */260for (j=0, i=0; i<k; i++) {261overlap = marker[l = nbrs[i]];262if (overlap >= ncommon ||263overlap >= elen-1 ||264overlap >= eptr[l+1]-eptr[l]-1)265nbrs[j++] = l;266marker[l] = 0;267}268269return j;270}271272273/*****************************************************************************/274/*! This function creates the (almost) nodal of a finite element mesh */275/*****************************************************************************/276void CreateGraphNodal(idx_t ne, idx_t nn, idx_t *eptr, idx_t *eind,277idx_t **r_xadj, idx_t **r_adjncy)278{279idx_t i, j, nnbrs;280idx_t *nptr, *nind;281idx_t *xadj, *adjncy;282idx_t *marker, *nbrs;283284285/* construct the node-element list first */286nptr = ismalloc(nn+1, 0, "CreateGraphNodal: nptr");287nind = imalloc(eptr[ne], "CreateGraphNodal: nind");288289for (i=0; i<ne; i++) {290for (j=eptr[i]; j<eptr[i+1]; j++)291nptr[eind[j]]++;292}293MAKECSR(i, nn, nptr);294295for (i=0; i<ne; i++) {296for (j=eptr[i]; j<eptr[i+1]; j++)297nind[nptr[eind[j]]++] = i;298}299SHIFTCSR(i, nn, nptr);300301302/* Allocate memory for xadj, since you know its size.303These are done using standard malloc as they are returned304to the calling function */305if ((xadj = (idx_t *)malloc((nn+1)*sizeof(idx_t))) == NULL)306gk_errexit(SIGMEM, "***Failed to allocate memory for xadj.\n");307*r_xadj = xadj;308iset(nn+1, 0, xadj);309310/* allocate memory for working arrays used by FindCommonElements */311marker = ismalloc(nn, 0, "CreateGraphNodal: marker");312nbrs = imalloc(nn, "CreateGraphNodal: nbrs");313314for (i=0; i<nn; i++) {315xadj[i] = FindCommonNodes(i, nptr[i+1]-nptr[i], nind+nptr[i], eptr,316eind, marker, nbrs);317}318MAKECSR(i, nn, xadj);319320/* Allocate memory for adjncy, since you now know its size.321These are done using standard malloc as they are returned322to the calling function */323if ((adjncy = (idx_t *)malloc(xadj[nn]*sizeof(idx_t))) == NULL) {324free(xadj);325*r_xadj = NULL;326gk_errexit(SIGMEM, "***Failed to allocate memory for adjncy.\n");327}328*r_adjncy = adjncy;329330for (i=0; i<nn; i++) {331nnbrs = FindCommonNodes(i, nptr[i+1]-nptr[i], nind+nptr[i], eptr,332eind, marker, nbrs);333for (j=0; j<nnbrs; j++)334adjncy[xadj[i]++] = nbrs[j];335}336SHIFTCSR(i, nn, xadj);337338gk_free((void **)&nptr, &nind, &marker, &nbrs, LTERM);339}340341342/*****************************************************************************/343/*! This function finds the union of nodes that are in the same elements with344the ``query'' node.345*/346/*****************************************************************************/347idx_t FindCommonNodes(idx_t qid, idx_t nelmnts, idx_t *elmntids, idx_t *eptr,348idx_t *eind, idx_t *marker, idx_t *nbrs)349{350idx_t i, ii, j, jj, k;351352/* find all nodes that share at least one element with qid */353marker[qid] = 1; /* this is to prevent self-loops */354for (k=0, i=0; i<nelmnts; i++) {355j = elmntids[i];356for (ii=eptr[j]; ii<eptr[j+1]; ii++) {357jj = eind[ii];358if (marker[jj] == 0) {359nbrs[k++] = jj;360marker[jj] = 1;361}362}363}364365/* reset the marker */366marker[qid] = 0;367for (i=0; i<k; i++) {368marker[nbrs[i]] = 0;369}370371return k;372}373374375376/*************************************************************************/377/*! This function creates and initializes a mesh_t structure */378/*************************************************************************/379mesh_t *CreateMesh(void)380{381mesh_t *mesh;382383mesh = (mesh_t *)gk_malloc(sizeof(mesh_t), "CreateMesh: mesh");384385InitMesh(mesh);386387return mesh;388}389390391/*************************************************************************/392/*! This function initializes a mesh_t data structure */393/*************************************************************************/394void InitMesh(mesh_t *mesh)395{396memset((void *)mesh, 0, sizeof(mesh_t));397}398399400/*************************************************************************/401/*! This function deallocates any memory stored in a mesh */402/*************************************************************************/403void FreeMesh(mesh_t **r_mesh)404{405mesh_t *mesh = *r_mesh;406407gk_free((void **)&mesh->eptr, &mesh->eind, &mesh->ewgt, &mesh, LTERM);408409*r_mesh = NULL;410}411412413414