void MESH_Renumber(Mesh_ptr mesh, int renum_type, MType mtype) { MVertex_ptr mv, v0=NULL; MEdge_ptr me, e0=NULL; MFace_ptr mf, f0=NULL; MRegion_ptr mr, r0=NULL; int idx, idx2, idx3; int i, j; int done; MAttrib_ptr vidatt; List_ptr vlist; double xyz[3]; double rval; int bandwidth, maxbandwidth1, maxbandwidth2; double avebandwidth1, avebandwidth2; void *pval; if (renum_type == 0) { if (mtype == MVERTEX || mtype == MALLTYPE) { int nv = 0; idx = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) MV_Set_ID(mv,++nv); } if (mtype == MEDGE || mtype == MALLTYPE) { int ne = 0; idx = 0; while ((me = MESH_Next_Edge(mesh,&idx))) ME_Set_ID(me,++ne); } if (mtype == MFACE || mtype == MALLTYPE) { int nf = 0; idx = 0; while ((mf = MESH_Next_Face(mesh,&idx))) MF_Set_ID(mf,++nf); } if (mtype == MREGION || mtype == MALLTYPE) { int nr = 0; idx = 0; while ((mr = MESH_Next_Region(mesh,&idx))) MR_Set_ID(mr,++nr); } } else if (renum_type == 1) { double minx, miny, minz; int minid, maxid; int *nadj, *newmap, *adj, *offset, nconn; int nalloc, depth, maxwidth; #ifdef MSTK_USE_MARKERS int mkid = MSTK_GetMarker(); #else MAttrib_ptr mkatt = MAttrib_New(mesh, "mkatt", INT, MALLTYPE); #endif if (mtype == MVERTEX || mtype == MALLTYPE) { int nv = MESH_Num_Vertices(mesh); /* Compute a graph of vertex connections across elements (faces for surface meshes, regions for solid meshes */ /* Start with the vertex in the lower leftmost corner */ minx = miny = minz = 1.0e+12; v0 = NULL; idx = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) { MV_Coords(mv,xyz); if (xyz[0] <= minx && xyz[1] <= miny && xyz[2] <= minz) { minx = xyz[0]; miny = xyz[1]; minz = xyz[2]; v0 = mv; } } nadj = (int *) malloc(nv*sizeof(int)); nalloc = nv*5; adj = (int *) malloc(nalloc*sizeof(int)); if (!MESH_Num_Regions(mesh)) { int nentries = 0; i = 0; idx = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) { List_ptr vfaces, adjvlist; MFace_ptr vf; MVertex_ptr adjv; adjvlist = List_New(0); vfaces = MV_Faces(mv); idx2 = 0; while ((vf = List_Next_Entry(vfaces,&idx2))) { List_ptr fverts = MF_Vertices(vf,1,0); idx3 = 0; while ((adjv = List_Next_Entry(fverts,&idx3))) { if (adjv != mv) { int vmarked; #ifdef MSTK_USE_MARKERS vmarked = MEnt_IsMarked(adjv,mkid); #else MEnt_Get_AttVal(adjv, mkatt, &vmarked, &rval, &pval); #endif if (!vmarked) { List_Add(adjvlist,adjv); #ifdef MSTK_USE_MARKERS MEnt_Mark(adjv,mkid); #else MEnt_Set_AttVal(adjv, mkatt, 1, 0.0, NULL); #endif } } } List_Delete(fverts); } List_Delete(vfaces); #ifdef MSTK_USE_MARKERS List_Unmark(adjvlist,mkid); #endif nadj[i] = List_Num_Entries(adjvlist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adjv = List_Next_Entry(adjvlist,&idx2))) adj[nentries++] = MV_ID(adjv)-1; List_Delete(adjvlist); i++; } } else { int nentries = 0; i = 0; idx = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) { List_ptr vregions, adjvlist; MRegion_ptr vr; MVertex_ptr adjv; adjvlist = List_New(0); vregions = MV_Regions(mv); idx2 = 0; while ((vr = List_Next_Entry(vregions,&idx2))) { List_ptr rverts = MR_Vertices(vr); idx3 = 0; while ((adjv = List_Next_Entry(rverts,&idx3))) { if (adjv != mv) { int vmarked; #ifdef MSTK_USE_MARKERS vmarked = MEnt_IsMarked(adjv,mkid); #else MEnt_Get_AttVal(adjv, mkatt, &vmarked, &rval, &pval); #endif if (!vmarked) { List_Add(adjvlist,adjv); #ifdef MSTK_USE_MARKERS MEnt_Mark(adjv,mkid); #else MEnt_Set_AttVal(adjv, mkatt, 1, 0.0, NULL); #endif } } } List_Delete(rverts); } List_Delete(vregions); #ifdef MSTK_USE_MARKERS List_Unmark(adjvlist,mkid); #endif nadj[i] = List_Num_Entries(adjvlist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adjv = List_Next_Entry(adjvlist,&idx2))) adj[nentries++] = MV_ID(adjv)-1; List_Delete(adjvlist); i++; } } /* Compute offsets into adj array */ offset = (int *) malloc(nv*sizeof(int)); offset[0] = 0; for (i = 1; i < nv; i++) offset[i] = offset[i-1] + nadj[i-1]; /* Compute maximum bandwidth before renumbering */ maxbandwidth1 = 0; avebandwidth1 = 0; for (i = 0; i < nv; i++) { int off = offset[i]; int curid = i; for (j = 0; j < nadj[i]; j++) { int adjid = adj[off+j]; int diff = abs(adjid-curid); maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1; avebandwidth1 += diff; nconn++; } } nconn = offset[nv-1]+nadj[nv-1]; avebandwidth1 /= nconn; fprintf(stderr, "Ave vertex ID difference on elements before renumbering: %-lf\n", avebandwidth1); fprintf(stderr, "Max vertex ID difference on elements before renumbering: %-d\n", maxbandwidth1); fprintf(stderr,"\n"); newmap = (int *) malloc(nv*sizeof(int)); Graph_Renumber_GPS(nv, MV_ID(v0)-1, nadj, adj, newmap, &depth, &maxwidth); /* Compute bandwidth after renumbering */ maxbandwidth2 = 0; avebandwidth2 = 0; for (i = 0; i < nv; i++) { int off = offset[i]; int curid = newmap[i]; for (j = 0; j < nadj[i]; j++) { int adjid = newmap[adj[off+j]]; int diff = abs(adjid-curid); maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2; avebandwidth2 += diff; nconn++; } } nconn = offset[nv-1]+nadj[nv-1]; avebandwidth2 /= nconn; if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) { /* Renumber */ idx = 0; i = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) { MV_Set_ID(mv,newmap[i]+1); i++; } fprintf(stderr, "Ave vertex ID difference on elements after renumbering: %-lf\n", avebandwidth2); fprintf(stderr, "Max vertex ID difference on elements after renumbering: %-d\n", maxbandwidth2); } else { nv = 0; idx = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) MV_Set_ID(mv,++nv); fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n"); } fprintf(stderr,"\n\n\n"); free(nadj); free(adj); free(offset); free(newmap); } /* Reorder edges according to a breadth first algorithm applied to edges (differs from RCM in that it does not add adjacent nodes in ascending order of their valence) */ if (mtype == MEDGE || mtype == MALLTYPE) { int ne = MESH_Num_Edges(mesh); MEdge_ptr ve; List_ptr elist; /************************* renumbering code ****************************/ ne = MESH_Num_Edges(mesh); if (mtype == MALLTYPE) { /* RCM algorithm already applied on the vertices. Use an edge connected to the starting vertex as the first edge */ List_ptr vedges = MV_Edges(v0); e0 = List_Entry(vedges,0); List_Delete(vedges); } else { /* Find the edge whose mid point is a minimum point */ minx = miny = minz = 1.0e+12; e0 = NULL; idx = 0; while ((me = MESH_Next_Edge(mesh,&idx))) { double exyz[2][3]; MV_Coords(ME_Vertex(me,0),exyz[0]); MV_Coords(ME_Vertex(me,1),exyz[1]); xyz[0] = (exyz[0][0]+exyz[1][0])/2.0; xyz[1] = (exyz[0][1]+exyz[1][1])/2.0; xyz[2] = (exyz[0][2]+exyz[1][2])/2.0; if (xyz[0] < minx && xyz[1] < miny && xyz[2] < minz) { minx = xyz[0]; miny = xyz[1]; minz = xyz[2]; e0 = me; } } } nadj = (int *) malloc(ne*sizeof(int)); nalloc = ne*5; adj = (int *) malloc(nalloc*sizeof(int)); if (!MESH_Num_Regions(mesh)) { int nentries = 0; i = 0; idx = 0; while ((me = MESH_Next_Edge(mesh,&idx))) { List_ptr efaces, adjelist; MFace_ptr ef; MEdge_ptr adje; adjelist = List_New(0); efaces = ME_Faces(me); idx2 = 0; while ((ef = List_Next_Entry(efaces,&idx2))) { List_ptr fedges = MF_Edges(ef,1,0); idx3 = 0; while ((adje = List_Next_Entry(fedges,&idx3))) { if (adje != me) { int emarked; #ifdef MSTK_USE_MARKERS emarked = MEnt_IsMarked(adje,mkid); #else MEnt_Get_AttVal(adje, mkatt, &emarked, &rval, &pval); #endif if (!emarked) { List_Add(adjelist,adje); #ifdef MSTK_USE_MARKERS MEnt_Mark(adje,mkid); #else MEnt_Set_AttVal(adje, mkatt, 1, 0.0, NULL); #endif } } } List_Delete(fedges); } List_Delete(efaces); #ifdef MSTK_USE_MARKERS List_Unmark(adjelist,mkid); #endif nadj[i] = List_Num_Entries(adjelist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adje = List_Next_Entry(adjelist,&idx2))) adj[nentries++] = ME_ID(adje)-1; List_Delete(adjelist); i++; } } else { int nentries = 0; i = 0; idx = 0; while ((me = MESH_Next_Edge(mesh,&idx))) { List_ptr eregions, adjelist; MRegion_ptr er; MEdge_ptr adje; adjelist = List_New(0); eregions = ME_Regions(me); idx2 = 0; while ((er = List_Next_Entry(eregions,&idx2))) { List_ptr redges = MR_Edges(er); idx3 = 0; while ((adje = List_Next_Entry(redges,&idx3))) { if (adje != me) { int emarked; #ifdef MSTK_USE_MARKERS emarked = MEnt_IsMarked(adje,mkid); #else MEnt_Get_AttVal(adje, mkatt, &emarked, &rval, &pval); #endif if (!emarked) { List_Add(adjelist,adje); #ifdef MSTK_USE_MARKERS MEnt_Mark(adje,mkid); #else MEnt_Set_AttVal(adje, mkatt, 1, 0.0, NULL); #endif } } } List_Delete(redges); } List_Delete(eregions); #ifdef MSTK_USE_MARKERS List_Unmark(adjelist,mkid); #endif nadj[i] = List_Num_Entries(adjelist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adje = List_Next_Entry(adjelist,&idx2))) adj[nentries++] = ME_ID(adje)-1; List_Delete(adjelist); i++; } } /* Compute offsets into adj array */ offset = (int *) malloc(ne*sizeof(int)); offset[0] = 0; for (i = 1; i < ne; i++) offset[i] = offset[i-1] + nadj[i-1]; /* Compute maximum bandwidth before renumbering */ maxbandwidth1 = 0; avebandwidth1 = 0; for (i = 0; i < ne; i++) { int off = offset[i]; int curid = i; for (j = 0; j < nadj[i]; j++) { int adjid = adj[off+j]; int diff = abs(adjid-curid); maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1; avebandwidth1 += diff; nconn++; } } nconn = offset[ne-1]+nadj[ne-1]; avebandwidth1 /= nconn; fprintf(stderr, "Ave edge ID difference on elements before renumbering: %-lf\n", avebandwidth1); fprintf(stderr, "Max edge ID difference on elements before renumbering: %-d\n", maxbandwidth1); fprintf(stderr,"\n"); /* Call Graph Renumbering algorithm */ newmap = (int *) malloc(ne*sizeof(int)); Graph_Renumber_GPS(ne, ME_ID(e0)-1, nadj, adj, newmap, &depth, &maxwidth); /* Compute bandwidth after renumbering */ maxbandwidth2 = 0; avebandwidth2 = 0; for (i = 0; i < ne; i++) { int off = offset[i]; int curid = newmap[i]; for (j = 0; j < nadj[i]; j++) { int adjid = newmap[adj[off+j]]; int diff = abs(adjid-curid); maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2; avebandwidth2 += diff; nconn++; } } nconn = offset[ne-1]+nadj[ne-1]; avebandwidth2 /= nconn; if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) { /* Renumber */ idx = 0; i = 0; while ((me = MESH_Next_Edge(mesh,&idx))) { ME_Set_ID(me,newmap[i]+1); i++; } fprintf(stderr, "Ave edge ID difference on elements after renumbering: %-lf\n", avebandwidth2); fprintf(stderr, "Max edge ID difference on elements after renumbering: %-d\n", maxbandwidth2); } else { ne = 0; idx = 0; while ((me = MESH_Next_Edge(mesh,&idx))) ME_Set_ID(me,++ne); fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n"); } fprintf(stderr,"\n\n\n"); free(nadj); free(adj); free(offset); free(newmap); } /* Reorder faces according to a breadth first algorithm applied to edges (differs from RCM in that it does not add adjacent graph nodes in ascending order of their valence) */ if (mtype == MFACE || mtype == MALLTYPE) { int nf = MESH_Num_Faces(mesh); if (mtype == MALLTYPE) { /* RCM algorithm already applied on the vertices. Use an edge connected to the starting vertex as the first edge */ List_ptr vfaces = MV_Faces(v0); f0 = List_Entry(vfaces,0); List_Delete(vfaces); } else { /* Find the face whose mid point is a minimum point */ minx = miny = minz = 1.0e+12; f0 = NULL; idx = 0; while ((mf = MESH_Next_Face(mesh,&idx))) { double fxyz[MAXPV2][3]; int nfv; MF_Coords(mf,&nfv,fxyz); xyz[0] = fxyz[0][0]; xyz[1] = fxyz[0][1]; xyz[2] = fxyz[0][2]; for (i = 1; i < nfv; i++) { xyz[0] += fxyz[i][0]; xyz[1] += fxyz[i][1]; xyz[2] += fxyz[i][2]; } xyz[0] /= nfv; xyz[1] /= nfv; xyz[2] /= nfv; if (xyz[0] < minx && xyz[1] < miny && xyz[2] < minz) { minx = xyz[0]; miny = xyz[1]; minz = xyz[2]; f0 = mf; } } } nadj = (int *) malloc(nf*sizeof(int)); nalloc = nf*5; adj = (int *) malloc(nalloc*sizeof(int)); if (!MESH_Num_Regions(mesh)) { int nentries = 0; i = 0; idx = 0; while ((mf = MESH_Next_Face(mesh,&idx))) { List_ptr vfaces, fverts, adjflist; MFace_ptr vf, adjf; MVertex_ptr fv; adjflist = List_New(0); fverts = MF_Vertices(mf,1,0); idx2 = 0; while ((fv = List_Next_Entry(fverts,&idx2))) { List_ptr vfaces = MV_Faces(fv); idx3 = 0; while ((adjf = List_Next_Entry(vfaces,&idx3))) { if (adjf != mf) { int fmarked; #ifdef MSTK_USE_MARKERS fmarked = MEnt_IsMarked(adjf,mkid); #else MEnt_Get_AttVal(adjf, mkatt, &fmarked, &rval, &pval); #endif if (fmarked) { List_Add(adjflist,adjf); #ifdef MSTK_USE_MARKERS MEnt_Mark(adjf,mkid); #else MEnt_Set_AttVal(adjf, mkatt, 1, 0.0, NULL); #endif } } } List_Delete(vfaces); } List_Delete(fverts); #ifdef MSTK_USE_MARKERS List_Unmark(adjflist,mkid); #endif nadj[i] = List_Num_Entries(adjflist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adjf = List_Next_Entry(adjflist,&idx2))) adj[nentries++] = MF_ID(adjf)-1; List_Delete(adjflist); i++; } } else { int nentries = 0; i = 0; idx = 0; while ((mf = MESH_Next_Face(mesh,&idx))) { List_ptr fregions, adjflist; MRegion_ptr fr; MFace_ptr adjf; adjflist = List_New(0); fregions = MF_Regions(mf); idx2 = 0; while ((fr = List_Next_Entry(fregions,&idx2))) { List_ptr rfaces = MR_Faces(fr); idx3 = 0; while ((adjf = List_Next_Entry(rfaces,&idx3))) { if (adjf != mf) { int fmarked; #ifdef MSTK_USE_MARKERS fmarked = MEnt_IsMarked(adjf,mkid); #else MEnt_Get_AttVal(adjf, mkatt, &fmarked, &rval, &pval); #endif if (fmarked) { List_Add(adjflist,adjf); #ifdef MSTK_USE_MARKERS MEnt_Mark(adjf,mkid); #else MEnt_Set_AttVal(adjf, mkatt, 1, 0.0, NULL); #endif } } } List_Delete(rfaces); } List_Delete(fregions); #ifdef MSTK_USE_MARKERS List_Unmark(adjflist,mkid); #endif nadj[i] = List_Num_Entries(adjflist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adjf = List_Next_Entry(adjflist,&idx2))) adj[nentries++] = MF_ID(adjf)-1; List_Delete(adjflist); i++; } } /* Compute offsets into adj array */ offset = (int *) malloc(nf*sizeof(int)); offset[0] = 0; for (i = 1; i < nf; i++) offset[i] = offset[i-1] + nadj[i-1]; /* Compute maximum bandwidth before renumbering */ maxbandwidth1 = 0; avebandwidth1 = 0; for (i = 0; i < nf; i++) { int off = offset[i]; int curid = i; for (j = 0; j < nadj[i]; j++) { int adjid = adj[off+j]; int diff = abs(adjid-curid); maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1; avebandwidth1 += diff; nconn++; } } nconn = offset[nf-1]+nadj[nf-1]; avebandwidth1 /= nconn; if (MESH_Num_Regions(mesh)) { fprintf(stderr, "Ave face ID difference on elements before renumbering: %-lf\n", avebandwidth1); fprintf(stderr, "Max face ID difference on elements before renumbering: %-d\n", maxbandwidth1); } else { fprintf(stderr, "Ave face ID difference before renumbering: %-lf\n", avebandwidth1); fprintf(stderr, "Max face ID difference before renumbering: %-d\n", maxbandwidth1); } fprintf(stderr,"\n"); /* Call Graph Renumbering algorithm */ newmap = (int *) malloc(nf*sizeof(int)); Graph_Renumber_GPS(nf, MF_ID(f0)-1, nadj, adj, newmap, &depth, &maxwidth); /* Compute bandwidth after renumbering */ maxbandwidth2 = 0; avebandwidth2 = 0; for (i = 0; i < nf; i++) { int off = offset[i]; int curid = newmap[i]; for (j = 0; j < nadj[i]; j++) { int adjid = newmap[adj[off+j]]; int diff = abs(adjid-curid); maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2; avebandwidth2 += diff; nconn++; } } nconn = offset[nf-1]+nadj[nf-1]; avebandwidth2 /= nconn; if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) { /* Renumber */ idx = 0; i = 0; while ((mf = MESH_Next_Face(mesh,&idx))) { MF_Set_ID(mf,newmap[i]+1); i++; } if (MESH_Num_Regions(mesh)) { fprintf(stderr, "Ave face ID difference on elements after renumbering: %-lf\n", avebandwidth2); fprintf(stderr, "Max face ID difference on elements after renumbering: %-d\n", maxbandwidth2); } else { fprintf(stderr, "Ave face ID difference after renumbering: %-lf\n", avebandwidth2); fprintf(stderr, "Max face ID difference after renumbering: %-d\n", maxbandwidth2); } } else { nf = 0; idx = 0; while ((mf = MESH_Next_Face(mesh,&idx))) MF_Set_ID(mf,++nf); fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n"); } fprintf(stderr,"\n\n\n"); free(nadj); free(adj); free(offset); free(newmap); } if (mtype == MREGION || mtype == MALLTYPE) { int nr = MESH_Num_Regions(mesh); if (nr) { if (mtype == MALLTYPE) { /* Renumbering algorithm already applied on the vertices. Use a region connected to the starting vertex as the first region */ List_ptr vregions = MV_Regions(v0); r0 = List_Entry(vregions,0); List_Delete(vregions); } else { /* Find the region whose center point is a minimum point */ minx = miny = minz = 1.0e+12; r0 = NULL; idx = 0; while ((mr = MESH_Next_Region(mesh,&idx))) { double rxyz[MAXPV3][3]; int nrv; MR_Coords(mr,&nrv,rxyz); xyz[0] = rxyz[0][0]; xyz[1] = rxyz[0][1]; xyz[2] = rxyz[0][2]; for (i = 1; i < nrv; i++) { xyz[0] += rxyz[i][0]; xyz[1] += rxyz[i][1]; xyz[2] += rxyz[i][2]; } xyz[0] /= nrv; xyz[1] /= nrv; xyz[2] /= nrv; if (xyz[0] < minx && xyz[1] < miny && xyz[2] < minz) { minx = xyz[0]; miny = xyz[1]; minz = xyz[2]; r0 = mr; } } } nadj = (int *) malloc(nr*sizeof(int)); nalloc = nr*5; adj = (int *) malloc(nalloc*sizeof(int)); int nentries = 0; i = 0; idx = 0; while ((mr = MESH_Next_Region(mesh,&idx))) { List_ptr vregions, rverts, adjrlist; MRegion_ptr vr, adjr; MVertex_ptr rv; adjrlist = List_New(0); rverts = MR_Vertices(mr); idx2 = 0; while ((rv = List_Next_Entry(rverts,&idx2))) { List_ptr vregions = MV_Regions(rv); idx3 = 0; while ((adjr = List_Next_Entry(vregions,&idx3))) { if (adjr != mr) { int rmarked; #ifdef MSTK_USE_MARKERS rmarked = MEnt_IsMarked(adjr,mkid); #else MEnt_Get_AttVal(adjr, mkatt, &rmarked, &rval, &pval); #endif List_Add(adjrlist,adjr); #ifdef MSTK_USE_MARKERS MEnt_Mark(adjr,mkid); #else MEnt_Set_AttVal(adjr, mkatt, 1, 0.0, NULL); #endif } } List_Delete(vregions); } List_Delete(rverts); #ifdef MSTK_USE_MARKERS List_Unmark(adjrlist,mkid); #endif nadj[i] = List_Num_Entries(adjrlist); if (nentries+nadj[i] > nalloc) { nalloc *= 2; adj = (int *) realloc(adj,nalloc*sizeof(int)); } idx2 = 0; while ((adjr = List_Next_Entry(adjrlist,&idx2))) adj[nentries++] = MR_ID(adjr)-1; List_Delete(adjrlist); i++; } /* Compute offsets into adj array */ offset = (int *) malloc(nr*sizeof(int)); offset[0] = 0; for (i = 1; i < nr; i++) offset[i] = offset[i-1] + nadj[i-1]; /* Compute maximum bandwidth before renumbering */ maxbandwidth1 = 0; avebandwidth1 = 0; for (i = 0; i < nr; i++) { int off = offset[i]; int curid = i; for (j = 0; j < nadj[i]; j++) { int adjid = adj[off+j]; int diff = abs(adjid-curid); maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1; avebandwidth1 += diff; nconn++; } } nconn = offset[nr-1]+nadj[nr-1]; avebandwidth1 /= nconn; fprintf(stderr, "Ave region ID difference before renumbering: %-lf\n", avebandwidth1); fprintf(stderr, "Max region ID difference before renumbering: %-d\n", maxbandwidth1); fprintf(stderr,"\n"); /* Call Graph Renumbering algorithm */ newmap = (int *) malloc(nr*sizeof(int)); Graph_Renumber_GPS(nr, MR_ID(r0)-1, nadj, adj, newmap, &depth, &maxwidth); /* Compute bandwidth after renumbering */ maxbandwidth2 = 0; avebandwidth2 = 0; for (i = 0; i < nr; i++) { int off = offset[i]; int curid = newmap[i]; for (j = 0; j < nadj[i]; j++) { int adjid = newmap[adj[off+j]]; int diff = abs(adjid-curid); maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2; avebandwidth2 += diff; nconn++; } } nconn = offset[nr-1]+nadj[nr-1]; avebandwidth2 /= nconn; if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) { /* Renumber */ idx = 0; i = 0; while ((mr = MESH_Next_Region(mesh,&idx))) { MR_Set_ID(mr,newmap[i]+1); i++; } fprintf(stderr, "Ave region ID difference after renumbering: %-lf\n", avebandwidth2); fprintf(stderr, "Max region ID difference after renumbering: %-d\n", maxbandwidth2); } else { nr = 0; idx = 0; while ((mr = MESH_Next_Region(mesh,&idx))) MR_Set_ID(mr,++nr); fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n"); } fprintf(stderr,"\n\n\n"); free(nadj); free(adj); free(offset); free(newmap); } } #ifdef MSTK_USE_MARKERS MSTK_FreeMarker(mkid); #endif } vidatt = MAttrib_New(mesh,"vidrcm",INT,MVERTEX); idx = 0; while ((mv = MESH_Next_Vertex(mesh,&idx))) { MEnt_Set_AttVal(mv,vidatt,MV_ID(mv),0.0,NULL); } /* We have to reset the max IDs stored in the mesh so that we can correctly assign IDs to new entities */ MESH_Reset_Cached_MaxIDs(mesh); return; }
int MESH_PartitionWithZoltan(Mesh_ptr mesh, int nparts, int **part, int noptions, char **options, MSTK_Comm comm) { MEdge_ptr fedge; MFace_ptr mf, oppf, rface; MRegion_ptr mr, oppr; List_ptr fedges, efaces, rfaces, fregions; int i, j, k, id; int nv, ne, nf, nr=0, nfe, nef, nfr, nrf, idx, idx2; int numflag, nedgecut, ipos; int wtflag; int rc; float ver; struct Zoltan_Struct *zz; GRAPH_DATA graph; int changes, numGidEntries, numLidEntries, numImport, numExport; ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids; int *importProcs, *importToPart, *exportProcs, *exportToPart; int rank; MPI_Comm_rank(comm,&rank); rc = Zoltan_Initialize(0, NULL, &ver); if (rc != ZOLTAN_OK){ MSTK_Report("MESH_PartitionWithZoltan","Could not initialize Zoltan",MSTK_FATAL); MPI_Finalize(); exit(0); } /****************************************************************** ** Create a Zoltan library structure for this instance of partition ********************************************************************/ zz = Zoltan_Create(comm); /***************************************************************** ** Figure out partitioning method *****************************************************************/ char partition_method_str[32]; strcpy(partition_method_str,"RCB"); /* Default - Recursive Coordinate Bisection */ if (noptions) { for (i = 0; i < noptions; i++) { if (strncmp(options[i],"LB_PARTITION",12) == 0) { char *result = NULL, instring[256]; strcpy(instring,options[i]); result = strtok(instring,"="); result = strtok(NULL," "); strcpy(partition_method_str,result); } } } if (rank == 0) { char mesg[256]; sprintf(mesg,"Using partitioning method %s for ZOLTAN\n",partition_method_str); MSTK_Report("MESH_PartitionWithZoltan",mesg,MSTK_MESG); } /* General parameters for Zoltan */ Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0"); Zoltan_Set_Param(zz, "LB_METHOD", partition_method_str); Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION"); Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1"); Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1"); Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL"); graph.numMyNodes = 0; graph.numAllNbors = 0; graph.nodeGID = NULL; graph.nodeCoords = NULL; graph.nborIndex = NULL; graph.nborGID = NULL; graph.nborProc = NULL; if (strcmp(partition_method_str,"RCB") == 0) { if (rank == 0) { nr = MESH_Num_Regions(mesh); nf = MESH_Num_Faces(mesh); if (!nf && !nr) MSTK_Report("MESH_PartitionWithZoltan","Cannot partition wire meshes", MSTK_FATAL); if (nr == 0) { /* Surface or planar mesh */ int ndim = 2; /* assume mesh is planar */ idx = 0; MVertex_ptr mv; while ((mv = MESH_Next_Vertex(mesh,&idx))) { double vxyz[3]; MV_Coords(mv,vxyz); if (vxyz[2] != 0.0) { ndim = 3; /* non-planar or planar with non-zero z */ break; } } NDIM_4_ZOLTAN = ndim-1; /* ignore last dimension to avoid partitioning in that dimension */ graph.numMyNodes = nf; graph.nodeGID = (ZOLTAN_ID_TYPE *) malloc(sizeof(ZOLTAN_ID_TYPE) * nf); graph.nodeCoords = (double *) malloc(sizeof(double) * NDIM_4_ZOLTAN * nf); idx = 0; while ((mf = MESH_Next_Face(mesh,&idx))) { double fxyz[MAXPV2][3], cen[3]; int nfv; MF_Coords(mf,&nfv,fxyz); cen[0] = cen[1] = cen[2] = 0.0; for (j = 0; j < nfv; j++) for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] += fxyz[j][k]; for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] /= nfv; id = MF_ID(mf); graph.nodeGID[id-1] = id; memcpy(&(graph.nodeCoords[NDIM_4_ZOLTAN*(id-1)]),cen,NDIM_4_ZOLTAN*sizeof(double)); } } else { /* Volume mesh */ int ndim = 3; NDIM_4_ZOLTAN = ndim-1; /* ignore last dimension to avoid partitioning in that dimension */ graph.numMyNodes = nr; graph.nodeGID = (ZOLTAN_ID_TYPE *) malloc(sizeof(ZOLTAN_ID_TYPE) * nr); graph.nodeCoords = (double *) malloc(sizeof(double) * NDIM_4_ZOLTAN * nr); idx = 0; while ((mr = MESH_Next_Region(mesh,&idx))) { double rxyz[MAXPV3][3], cen[3]; int nrv; MR_Coords(mr,&nrv,rxyz); cen[0] = cen[1] = cen[2] = 0.0; for (j = 0; j < nrv; j++) for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] += rxyz[j][k]; for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] /= nrv; for (k = 0; k < NDIM_4_ZOLTAN; k++) if (fabs(cen[k]) < 1.0e-10) cen[k] = 0.0; id = MR_ID(mr); graph.nodeGID[id-1] = id; memcpy(&(graph.nodeCoords[NDIM_4_ZOLTAN*(id-1)]),cen,NDIM_4_ZOLTAN*sizeof(double)); } } } MPI_Bcast(&NDIM_4_ZOLTAN,1,MPI_INT,0,comm); /* Set some default values */ Zoltan_Set_Param(zz, "RCB_RECTILINEAR_BLOCKS","1"); // Zoltan_Set_Param(zz, "AVERAGE_CUTS", "1"); if (noptions > 1) { for (i = 1; i < noptions; i++) { char *paramstr = NULL, *valuestr = NULL, instring[256]; strcpy(instring,options[i]); paramstr = strtok(instring,"="); valuestr = strtok(NULL," "); Zoltan_Set_Param(zz,paramstr,valuestr); } } /* Query functions - defined in simpleQueries.h */ Zoltan_Set_Num_Obj_Fn(zz, get_number_of_nodes, &graph); Zoltan_Set_Obj_List_Fn(zz, get_node_list, &graph); Zoltan_Set_Num_Geom_Fn(zz, get_num_dimensions_reduced, &graph); /* reduced dimensions */ Zoltan_Set_Geom_Multi_Fn(zz, get_element_centers_reduced, &graph); /* reduced dimension centers */ } else if (strcmp(partition_method_str,"GRAPH") == 0) { if(rank == 0) { nv = MESH_Num_Vertices(mesh); ne = MESH_Num_Edges(mesh); nf = MESH_Num_Faces(mesh); nr = MESH_Num_Regions(mesh); ipos = 0; /* build nodes and neighbors list, similar as in partition with metis Assign processor 0 the whole mesh, assign other processors a NULL mesh */ if (nr == 0) { if (nf == 0) { MSTK_Report("MESH_PartitionWithZoltan", "Cannot partition wire meshes with Zoltan",MSTK_FATAL); exit(-1); } graph.nodeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nf); graph.nborIndex = (int *)malloc(sizeof(int) * (nf + 1)); graph.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * 2*ne); graph.nborProc = (int *)malloc(sizeof(int) * 2*ne); graph.nborIndex[0] = 0; /* Surface mesh */ idx = 0; i = 0; while ((mf = MESH_Next_Face(mesh,&idx))) { graph.nodeGID[i] = MF_ID(mf); fedges = MF_Edges(mf,1,0); nfe = List_Num_Entries(fedges); idx2 = 0; while ((fedge = List_Next_Entry(fedges,&idx2))) { efaces = ME_Faces(fedge); nef = List_Num_Entries(efaces); if (nef == 1) { continue; /* boundary edge; nothing to do */ } else { int j; for (j = 0; j < nef; j++) { oppf = List_Entry(efaces,j); if (oppf == mf) { graph.nborGID[ipos] = MF_ID(oppf); /* initially set all nodes on processor 0 */ graph.nborProc[ipos] = 0; ipos++; } } } List_Delete(efaces); } List_Delete(fedges); i++; graph.nborIndex[i] = ipos; } graph.numMyNodes = i; graph.numAllNbors = ipos; } else { graph.nodeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nr); graph.nborIndex = (int *)malloc(sizeof(int) * (nr + 1)); graph.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * 2*nf); graph.nborProc = (int *)malloc(sizeof(int) * 2*nf); graph.nborIndex[0] = 0; /* Volume mesh */ idx = 0; i = 0; while ((mr = MESH_Next_Region(mesh,&idx))) { graph.nodeGID[i] = MR_ID(mr); rfaces = MR_Faces(mr); nrf = List_Num_Entries(rfaces); idx2 = 0; while ((rface = List_Next_Entry(rfaces,&idx2))) { fregions = MF_Regions(rface); nfr = List_Num_Entries(fregions); if (nfr > 1) { oppr = List_Entry(fregions,0); if (oppr == mr) oppr = List_Entry(fregions,1); graph.nborGID[ipos] = MR_ID(oppr); /* initially set all nodes on processor 0 */ graph.nborProc[ipos] = 0; ipos++; } List_Delete(fregions); } List_Delete(rfaces); i++; graph.nborIndex[i] = ipos; } graph.numMyNodes = i; graph.numAllNbors = ipos; } } /* Graph parameters */ /* Zoltan_Set_Param(zz, "CHECK_GRAPH", "2"); */ Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35"); /* 0-remove all, 1-remove none */ /* Query functions - defined in simpleQueries.h */ Zoltan_Set_Num_Obj_Fn(zz, get_number_of_nodes, &graph); Zoltan_Set_Obj_List_Fn(zz, get_node_list, &graph); Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &graph); Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &graph); } /* Partition the graph */ /****************************************************************** ** Zoltan can now partition the graph. ** We assume the number of partitions is ** equal to the number of processes. Process rank 0 will own ** partition 0, process rank 1 will own partition 1, and so on. ******************************************************************/ rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */ &changes, /* 1 if partitioning was changed, 0 otherwise */ &numGidEntries, /* Number of integers used for a global ID */ &numLidEntries, /* Number of integers used for a local ID */ &numImport, /* Number of nodes to be sent to me */ &importGlobalGids, /* Global IDs of nodes to be sent to me */ &importLocalGids, /* Local IDs of nodes to be sent to me */ &importProcs, /* Process rank for source of each incoming node */ &importToPart, /* New partition for each incoming node */ &numExport, /* Number of nodes I must send to other processes*/ &exportGlobalGids, /* Global IDs of the nodes I must send */ &exportLocalGids, /* Local IDs of the nodes I must send */ &exportProcs, /* Process to which I send each of the nodes */ &exportToPart); /* Partition to which each node will belong */ if (rc != ZOLTAN_OK){ if (rank == 0) MSTK_Report("MESH_PartitionWithZoltan","Could not partition mesh with ZOLTAN", MSTK_ERROR); Zoltan_Destroy(&zz); MPI_Finalize(); return 0; } if(rank == 0) { *part = (int *) calloc(graph.numMyNodes,sizeof(int)); for ( i = 0; i < numExport; i++ ) { (*part)[exportGlobalGids[i]-1] = exportToPart[i]; } if (graph.nodeGID) free(graph.nodeGID); if (graph.nodeCoords) free(graph.nodeCoords); if (graph.nborIndex) free(graph.nborIndex); if (graph.nborGID) free(graph.nborGID); if (graph.nborProc) free(graph.nborProc); } else { *part = NULL; } Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids, &exportProcs, &exportToPart); Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids, &importProcs, &importToPart); Zoltan_Destroy(&zz); return 1; }