2
* Copyright 1997, Regents of the University of Minnesota
6
* This file contains routines for converting 3D and 4D finite element
7
* meshes into dual or nodal graphs
12
* $Id: mesh.c 13804 2013-03-04 23:49:08Z karypis $
19
/*****************************************************************************/
20
/*! This function creates a graph corresponding to the dual of a finite element
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;
55
if ((sigrval = gk_sigcatch()) != 0)
59
/* renumber the mesh */
61
ChangeMesh2CNumbering(*ne, eptr, eind);
65
/* create dual graph */
66
*r_xadj = *r_adjncy = NULL;
67
CreateGraphDual(*ne, *nn, eptr, eind, *ncommon, r_xadj, r_adjncy);
72
ChangeMesh2FNumbering(*ne, eptr, eind, *ne, *r_xadj, *r_adjncy);
80
if (*r_adjncy != NULL)
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;
125
if ((sigrval = gk_sigcatch()) != 0)
129
/* renumber the mesh */
131
ChangeMesh2CNumbering(*ne, eptr, eind);
135
/* create nodal graph */
136
*r_xadj = *r_adjncy = NULL;
137
CreateGraphNodal(*ne, *nn, eptr, eind, r_xadj, r_adjncy);
142
ChangeMesh2FNumbering(*ne, eptr, eind, *nn, *r_xadj, *r_adjncy);
145
gk_malloc_cleanup(0);
150
if (*r_adjncy != NULL)
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)
167
idx_t *xadj, *adjncy;
168
idx_t *marker, *nbrs;
171
printf(" Increased ncommon to 1, as it was initially %"PRIDX"\n", ncommon);
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++)
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");
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) {
216
gk_errexit(SIGMEM, "***Failed to allocate memory for adjncy.\n");
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++) {
245
for (ii=nptr[j]; ii<nptr[j+1]; ii++) {
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)
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 ||
265
overlap >= eptr[l+1]-eptr[l]-1)
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)
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++)
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");
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,
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) {
327
gk_errexit(SIGMEM, "***Failed to allocate memory for adjncy.\n");
331
for (i=0; i<nn; i++) {
332
nnbrs = FindCommonNodes(i, nptr[i+1]-nptr[i], nind+nptr[i], eptr,
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
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++) {
357
for (ii=eptr[j]; ii<eptr[j+1]; ii++) {
359
if (marker[jj] == 0) {
366
/* reset the marker */
368
for (i=0; i<k; i++) {
377
/*************************************************************************/
378
/*! This function creates and initializes a mesh_t structure */
379
/*************************************************************************/
380
mesh_t *CreateMesh(void)
384
mesh = (mesh_t *)gk_malloc(sizeof(mesh_t), "CreateMesh: 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);