Bug #1267: Integrate METIS graph partitioning library
[charm.git] / src / libs / ck-libs / metis / libmetis / mesh.c
blob3c5261211232b3290b7e9aa3327e145f88482927
1 /*
2 * Copyright 1997, Regents of the University of Minnesota
4 * mesh.c
6 * This file contains routines for converting 3D and 4D finite element
7 * meshes into dual or nodal graphs
9 * Started 8/18/97
10 * George
12 * $Id: mesh.c 13804 2013-03-04 23:49:08Z karypis $
16 #include "metislib.h"
19 /*****************************************************************************/
20 /*! This function creates a graph corresponding to the dual of a finite element
21 mesh.
23 \param ne is the number of elements in the mesh.
24 \param nn is the number of nodes in the mesh.
25 \param eptr is an array of size ne+1 used to mark the start and end
26 locations in the nind array.
27 \param eind is an array that stores for each element the set of node IDs
28 (indices) that it is made off. The length of this array is equal
29 to the total number of nodes over all the mesh elements.
30 \param ncommon is the minimum number of nodes that two elements must share
31 in order to be connected via an edge in the dual graph.
32 \param numflag is either 0 or 1 indicating if the numbering of the nodes
33 starts from 0 or 1, respectively. The same numbering is used for the
34 returned graph as well.
35 \param r_xadj indicates where the adjacency list of each vertex is stored
36 in r_adjncy. The memory for this array is allocated by this routine.
37 It can be freed by calling METIS_free().
38 \param r_adjncy stores the adjacency list of each vertex in the generated
39 dual graph. The memory for this array is allocated by this routine.
40 It can be freed by calling METIS_free().
43 /*****************************************************************************/
44 int METIS_MeshToDual(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind,
45 idx_t *ncommon, idx_t *numflag, idx_t **r_xadj, idx_t **r_adjncy)
47 int sigrval=0, renumber=0;
49 /* set up malloc cleaning code and signal catchers */
50 if (!gk_malloc_init())
51 return METIS_ERROR_MEMORY;
53 gk_sigtrap();
55 if ((sigrval = gk_sigcatch()) != 0)
56 goto SIGTHROW;
59 /* renumber the mesh */
60 if (*numflag == 1) {
61 ChangeMesh2CNumbering(*ne, eptr, eind);
62 renumber = 1;
65 /* create dual graph */
66 *r_xadj = *r_adjncy = NULL;
67 CreateGraphDual(*ne, *nn, eptr, eind, *ncommon, r_xadj, r_adjncy);
70 SIGTHROW:
71 if (renumber)
72 ChangeMesh2FNumbering(*ne, eptr, eind, *ne, *r_xadj, *r_adjncy);
74 gk_siguntrap();
75 gk_malloc_cleanup(0);
77 if (sigrval != 0) {
78 if (*r_xadj != NULL)
79 free(*r_xadj);
80 if (*r_adjncy != NULL)
81 free(*r_adjncy);
82 *r_xadj = *r_adjncy = NULL;
85 return metis_rcode(sigrval);
89 /*****************************************************************************/
90 /*! This function creates a graph corresponding to (almost) the nodal of a
91 finite element mesh. In the nodal graph, each node is connected to the
92 nodes corresponding to the union of nodes present in all the elements
93 in which that node belongs.
95 \param ne is the number of elements in the mesh.
96 \param nn is the number of nodes in the mesh.
97 \param eptr is an array of size ne+1 used to mark the start and end
98 locations in the nind array.
99 \param eind is an array that stores for each element the set of node IDs
100 (indices) that it is made off. The length of this array is equal
101 to the total number of nodes over all the mesh elements.
102 \param numflag is either 0 or 1 indicating if the numbering of the nodes
103 starts from 0 or 1, respectively. The same numbering is used for the
104 returned graph as well.
105 \param r_xadj indicates where the adjacency list of each vertex is stored
106 in r_adjncy. The memory for this array is allocated by this routine.
107 It can be freed by calling METIS_free().
108 \param r_adjncy stores the adjacency list of each vertex in the generated
109 dual graph. The memory for this array is allocated by this routine.
110 It can be freed by calling METIS_free().
113 /*****************************************************************************/
114 int METIS_MeshToNodal(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind,
115 idx_t *numflag, idx_t **r_xadj, idx_t **r_adjncy)
117 int sigrval=0, renumber=0;
119 /* set up malloc cleaning code and signal catchers */
120 if (!gk_malloc_init())
121 return METIS_ERROR_MEMORY;
123 gk_sigtrap();
125 if ((sigrval = gk_sigcatch()) != 0)
126 goto SIGTHROW;
129 /* renumber the mesh */
130 if (*numflag == 1) {
131 ChangeMesh2CNumbering(*ne, eptr, eind);
132 renumber = 1;
135 /* create nodal graph */
136 *r_xadj = *r_adjncy = NULL;
137 CreateGraphNodal(*ne, *nn, eptr, eind, r_xadj, r_adjncy);
140 SIGTHROW:
141 if (renumber)
142 ChangeMesh2FNumbering(*ne, eptr, eind, *nn, *r_xadj, *r_adjncy);
144 gk_siguntrap();
145 gk_malloc_cleanup(0);
147 if (sigrval != 0) {
148 if (*r_xadj != NULL)
149 free(*r_xadj);
150 if (*r_adjncy != NULL)
151 free(*r_adjncy);
152 *r_xadj = *r_adjncy = NULL;
155 return metis_rcode(sigrval);
159 /*****************************************************************************/
160 /*! This function creates the dual of a finite element mesh */
161 /*****************************************************************************/
162 void CreateGraphDual(idx_t ne, idx_t nn, idx_t *eptr, idx_t *eind, idx_t ncommon,
163 idx_t **r_xadj, idx_t **r_adjncy)
165 idx_t i, j, nnbrs;
166 idx_t *nptr, *nind;
167 idx_t *xadj, *adjncy;
168 idx_t *marker, *nbrs;
170 if (ncommon < 1) {
171 printf(" Increased ncommon to 1, as it was initially %"PRIDX"\n", ncommon);
172 ncommon = 1;
175 /* construct the node-element list first */
176 nptr = ismalloc(nn+1, 0, "CreateGraphDual: nptr");
177 nind = imalloc(eptr[ne], "CreateGraphDual: nind");
179 for (i=0; i<ne; i++) {
180 for (j=eptr[i]; j<eptr[i+1]; j++)
181 nptr[eind[j]]++;
183 MAKECSR(i, nn, nptr);
185 for (i=0; i<ne; i++) {
186 for (j=eptr[i]; j<eptr[i+1]; j++)
187 nind[nptr[eind[j]]++] = i;
189 SHIFTCSR(i, nn, nptr);
192 /* Allocate memory for xadj, since you know its size.
193 These are done using standard malloc as they are returned
194 to the calling function */
195 if ((xadj = (idx_t *)malloc((ne+1)*sizeof(idx_t))) == NULL)
196 gk_errexit(SIGMEM, "***Failed to allocate memory for xadj.\n");
197 *r_xadj = xadj;
198 iset(ne+1, 0, xadj);
200 /* allocate memory for working arrays used by FindCommonElements */
201 marker = ismalloc(ne, 0, "CreateGraphDual: marker");
202 nbrs = imalloc(ne, "CreateGraphDual: nbrs");
204 for (i=0; i<ne; i++) {
205 xadj[i] = FindCommonElements(i, eptr[i+1]-eptr[i], eind+eptr[i], nptr,
206 nind, eptr, ncommon, marker, nbrs);
208 MAKECSR(i, ne, xadj);
210 /* Allocate memory for adjncy, since you now know its size.
211 These are done using standard malloc as they are returned
212 to the calling function */
213 if ((adjncy = (idx_t *)malloc(xadj[ne]*sizeof(idx_t))) == NULL) {
214 free(xadj);
215 *r_xadj = NULL;
216 gk_errexit(SIGMEM, "***Failed to allocate memory for adjncy.\n");
218 *r_adjncy = adjncy;
220 for (i=0; i<ne; i++) {
221 nnbrs = FindCommonElements(i, eptr[i+1]-eptr[i], eind+eptr[i], nptr,
222 nind, eptr, ncommon, marker, nbrs);
223 for (j=0; j<nnbrs; j++)
224 adjncy[xadj[i]++] = nbrs[j];
226 SHIFTCSR(i, ne, xadj);
228 gk_free((void **)&nptr, &nind, &marker, &nbrs, LTERM);
232 /*****************************************************************************/
233 /*! This function finds all elements that share at least ncommon nodes with
234 the ``query'' element.
236 /*****************************************************************************/
237 idx_t FindCommonElements(idx_t qid, idx_t elen, idx_t *eind, idx_t *nptr,
238 idx_t *nind, idx_t *eptr, idx_t ncommon, idx_t *marker, idx_t *nbrs)
240 idx_t i, ii, j, jj, k, l, overlap;
242 /* find all elements that share at least one node with qid */
243 for (k=0, i=0; i<elen; i++) {
244 j = eind[i];
245 for (ii=nptr[j]; ii<nptr[j+1]; ii++) {
246 jj = nind[ii];
248 if (marker[jj] == 0)
249 nbrs[k++] = jj;
250 marker[jj]++;
254 /* put qid into the neighbor list (in case it is not there) so that it
255 will be removed in the next step */
256 if (marker[qid] == 0)
257 nbrs[k++] = qid;
258 marker[qid] = 0;
260 /* compact the list to contain only those with at least ncommon nodes */
261 for (j=0, i=0; i<k; i++) {
262 overlap = marker[l = nbrs[i]];
263 if (overlap >= ncommon ||
264 overlap >= elen-1 ||
265 overlap >= eptr[l+1]-eptr[l]-1)
266 nbrs[j++] = l;
267 marker[l] = 0;
270 return j;
274 /*****************************************************************************/
275 /*! This function creates the (almost) nodal of a finite element mesh */
276 /*****************************************************************************/
277 void CreateGraphNodal(idx_t ne, idx_t nn, idx_t *eptr, idx_t *eind,
278 idx_t **r_xadj, idx_t **r_adjncy)
280 idx_t i, j, nnbrs;
281 idx_t *nptr, *nind;
282 idx_t *xadj, *adjncy;
283 idx_t *marker, *nbrs;
286 /* construct the node-element list first */
287 nptr = ismalloc(nn+1, 0, "CreateGraphNodal: nptr");
288 nind = imalloc(eptr[ne], "CreateGraphNodal: nind");
290 for (i=0; i<ne; i++) {
291 for (j=eptr[i]; j<eptr[i+1]; j++)
292 nptr[eind[j]]++;
294 MAKECSR(i, nn, nptr);
296 for (i=0; i<ne; i++) {
297 for (j=eptr[i]; j<eptr[i+1]; j++)
298 nind[nptr[eind[j]]++] = i;
300 SHIFTCSR(i, nn, nptr);
303 /* Allocate memory for xadj, since you know its size.
304 These are done using standard malloc as they are returned
305 to the calling function */
306 if ((xadj = (idx_t *)malloc((nn+1)*sizeof(idx_t))) == NULL)
307 gk_errexit(SIGMEM, "***Failed to allocate memory for xadj.\n");
308 *r_xadj = xadj;
309 iset(nn+1, 0, xadj);
311 /* allocate memory for working arrays used by FindCommonElements */
312 marker = ismalloc(nn, 0, "CreateGraphNodal: marker");
313 nbrs = imalloc(nn, "CreateGraphNodal: nbrs");
315 for (i=0; i<nn; i++) {
316 xadj[i] = FindCommonNodes(i, nptr[i+1]-nptr[i], nind+nptr[i], eptr,
317 eind, marker, nbrs);
319 MAKECSR(i, nn, xadj);
321 /* Allocate memory for adjncy, since you now know its size.
322 These are done using standard malloc as they are returned
323 to the calling function */
324 if ((adjncy = (idx_t *)malloc(xadj[nn]*sizeof(idx_t))) == NULL) {
325 free(xadj);
326 *r_xadj = NULL;
327 gk_errexit(SIGMEM, "***Failed to allocate memory for adjncy.\n");
329 *r_adjncy = adjncy;
331 for (i=0; i<nn; i++) {
332 nnbrs = FindCommonNodes(i, nptr[i+1]-nptr[i], nind+nptr[i], eptr,
333 eind, marker, nbrs);
334 for (j=0; j<nnbrs; j++)
335 adjncy[xadj[i]++] = nbrs[j];
337 SHIFTCSR(i, nn, xadj);
339 gk_free((void **)&nptr, &nind, &marker, &nbrs, LTERM);
343 /*****************************************************************************/
344 /*! This function finds the union of nodes that are in the same elements with
345 the ``query'' node.
347 /*****************************************************************************/
348 idx_t FindCommonNodes(idx_t qid, idx_t nelmnts, idx_t *elmntids, idx_t *eptr,
349 idx_t *eind, idx_t *marker, idx_t *nbrs)
351 idx_t i, ii, j, jj, k;
353 /* find all nodes that share at least one element with qid */
354 marker[qid] = 1; /* this is to prevent self-loops */
355 for (k=0, i=0; i<nelmnts; i++) {
356 j = elmntids[i];
357 for (ii=eptr[j]; ii<eptr[j+1]; ii++) {
358 jj = eind[ii];
359 if (marker[jj] == 0) {
360 nbrs[k++] = jj;
361 marker[jj] = 1;
366 /* reset the marker */
367 marker[qid] = 0;
368 for (i=0; i<k; i++) {
369 marker[nbrs[i]] = 0;
372 return k;
377 /*************************************************************************/
378 /*! This function creates and initializes a mesh_t structure */
379 /*************************************************************************/
380 mesh_t *CreateMesh(void)
382 mesh_t *mesh;
384 mesh = (mesh_t *)gk_malloc(sizeof(mesh_t), "CreateMesh: mesh");
386 InitMesh(mesh);
388 return mesh;
392 /*************************************************************************/
393 /*! This function initializes a mesh_t data structure */
394 /*************************************************************************/
395 void InitMesh(mesh_t *mesh)
397 memset((void *)mesh, 0, sizeof(mesh_t));
401 /*************************************************************************/
402 /*! This function deallocates any memory stored in a mesh */
403 /*************************************************************************/
404 void FreeMesh(mesh_t **r_mesh)
406 mesh_t *mesh = *r_mesh;
408 gk_free((void **)&mesh->eptr, &mesh->eind, &mesh->ewgt, &mesh, LTERM);
410 *r_mesh = NULL;