00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "ParFUM.h"
00018 #include "ParFUM_internals.h"
00019 #include <metis.h>
00020
00021
00022 class NList
00023 {
00024 int nn;
00025 int sn;
00026 int *elts;
00027 static int cmp(const void *v1, const void *v2);
00028 public:
00029 NList(void) { sn = 0; nn = 0; elts = 0; }
00030 void init(int _sn) { sn = _sn; nn = 0; elts = new int[sn]; }
00031 void add(int elt);
00032 int found(int elt);
00033 void sort(void) { qsort(elts, nn, sizeof(int), cmp); };
00034 int getnn(void) { return nn; }
00035 int getelt(int n) { assert(n < nn); return elts[n]; }
00036 ~NList() { delete [] elts; }
00037 };
00038
00039 class Nodes
00040 {
00041 int nnodes;
00042 NList *elts;
00043 public:
00044 Nodes(int _nnodes);
00045 ~Nodes() { delete [] elts; }
00046 void add(int node, int elem);
00047 int nelems(int node)
00048 {
00049 assert(node < nnodes);
00050 return elts[node].getnn();
00051 }
00052 int getelt(int node, int n)
00053 {
00054 assert(node < nnodes);
00055 return elts[node].getelt(n);
00056 }
00057 };
00058
00059 class Graph
00060 {
00061 int nelems;
00062 NList *nbrs;
00063 public:
00064 Graph(int elems);
00065 ~Graph() { delete [] nbrs; }
00066 void add(int elem1, int elem2);
00067 int elems(int elem)
00068 {
00069 assert(elem<nelems);
00070 return nbrs[elem].getnn();
00071 }
00072 void toAdjList(int *&adjStart,int *&adjList);
00073 };
00074
00075 int NList::cmp(const void *v1, const void *v2)
00076 {
00077 int *e1 = (int *) v1;
00078 int *e2 = (int *) v2;
00079 if(*e1==*e2) return 0;
00080 else if(*e1 < *e2) return -1;
00081 else return 1;
00082 }
00083
00084 void NList::add(int elt)
00085 {
00086
00087
00088
00089
00090 if (sn <= nn) {
00091 sn *= 2;
00092 int *telts = new int[sn];
00093 for (int i=0; i<nn; i++)
00094 telts[i] = elts[i];
00095 delete[] elts;
00096 elts = telts;
00097 }
00098
00099
00100 elts[nn++] = elt;
00101 }
00102
00103 int NList::found(int elt)
00104 {
00105 for(int i = 0; i < nn; i++)
00106 {
00107 if(elts[i] == elt)
00108 return 1;
00109 }
00110 return 0;
00111 }
00112
00113 Nodes::Nodes(int _nnodes)
00114 {
00115 nnodes = _nnodes;
00116 elts = new NList[nnodes];
00117
00118 for(int i=0; i<nnodes; i++) {
00119 elts[i].init(10);
00120 }
00121 }
00122
00123 void Nodes::add(int node, int elem)
00124 {
00125 assert(node < nnodes);
00126 elts[node].add(elem);
00127 }
00128
00129 Graph::Graph(int _nelems)
00130 {
00131 nelems = _nelems;
00132 nbrs = new NList[nelems];
00133
00134 for(int i=0; i<nelems; i++)
00135 {
00136 nbrs[i].init(10);
00137 }
00138 }
00139
00140 void Graph::add(int elem1, int elem2)
00141 {
00142 assert(elem1 < nelems);
00143 assert(elem2 < nelems);
00144
00145
00146
00147 if(!nbrs[elem1].found(elem2))
00148 {
00149 nbrs[elem1].add(elem2);
00150 nbrs[elem2].add(elem1);
00151 }
00152 }
00153
00154
00155 void Graph::toAdjList(int *&adjStart,int *&adjList)
00156 {
00157 int e,i;
00158 adjStart=new int[nelems+1];
00159 adjStart[0]=0;
00160 for (e=0;e<nelems;e++)
00161 adjStart[e+1]=adjStart[e]+elems(e);
00162 adjList=new int[adjStart[nelems]];
00163 int *adjOut=adjList;
00164 for (e=0;e<nelems;e++)
00165 for (i=nbrs[e].getnn()-1;i>=0;i--)
00166 *(adjOut++)=nbrs[e].getelt(i);
00167 }
00168
00169
00170 void mesh2graph(const FEM_Mesh *m, Graph *g)
00171 {
00172 Nodes nl(m->node.size());
00173
00174
00175 int globalCount=0,t,e,n;
00176 for(t=0;t<m->elem.size();t++)
00177 if (m->elem.has(t)) {
00178 const FEM_Elem &k=m->elem[t];
00179 for(e=0;e<k.size();e++,globalCount++)
00180 for(n=0;n<k.getNodesPer();n++)
00181 nl.add(k.getConn(e,n),globalCount);
00182 }
00183
00184
00185
00186
00187 int i, j;
00188 for(i = 0; i < m->node.size(); i++) {
00189 int nn = nl.nelems(i);
00190 for(j = 0; j < nn; j++) {
00191 int e1 = nl.getelt(i, j);
00192 for(int k = j + 1; k < nn; k++) {
00193 int e2 = nl.getelt(i, k);
00194 g->add(e1, e2);
00195 }
00196 }
00197 }
00198 }
00199
00200
00210 void mesh2graph_face(const FEM_Mesh* m, Graph* g)
00211 {
00212 const int faceMap2d_tri[3][2] = {{0,1},{1,2},{2,0}};
00213 const int faceMap3d_tet[4][3] = {{0,1,2},{0,3,1},{0,2,3},{1,3,2}};
00214 const int faceMap3d_hex[6][4] = {{0,1,2,3},{1,5,6,2},{2,6,7,3},
00215 {3,7,4,0},{0,4,5,1},{5,4,6,7}};
00216
00217
00218 std::map<int, std::set<int> > nodeNeighbors;
00219 int elementCount=0;
00220 for (int type=0; type<m->elem.size(); ++type) {
00221 if (!m->elem.has(type)) continue;
00222 const FEM_Elem& elems = m->elem[type];
00223 const int nodesPerElem = elems.getNodesPer();
00224 for (int elem=0; elem<elems.size(); ++elem,++elementCount) {
00225 for (int node=0; node<nodesPerElem; ++node) {
00226 nodeNeighbors[elems.getConn(elem, node)].insert(elementCount);
00227 }
00228 }
00229 }
00230
00231
00232 for (int type=0; type<m->elem.size(); ++type) {
00233 if (!m->elem.has(type)) continue;
00234 const FEM_Elem& elems = m->elem[type];
00235 const int nodesPerElem = elems.getNodesPer();
00236 int* faces;
00237 int faceSize;
00238
00239
00240 switch (nodesPerElem) {
00241 case 3:
00242 faces = (int*)faceMap2d_tri;
00243 faceSize = 2;
00244 break;
00245 case 4:
00246 faces = (int*)faceMap3d_tet;
00247 faceSize = 3;
00248 break;
00249 case 6:
00250 faces = (int*)faceMap3d_hex;
00251 faceSize = 4;
00252 break;
00253 default:
00254 CkPrintf("Cannot determine face neighbors for elements with %d nodes\n", nodesPerElem);
00255 CkAbort("Confused by element type during initial partitioning, aborting.");
00256 }
00257
00258 for (int elem=0; elem<elems.size(); ++elem,++elementCount) {
00259
00260
00261 for (int face=0; face<nodesPerElem; ++face) {
00262 std::set<int> elemNeighbors =
00263 nodeNeighbors[elems.getConn(elem, faces[face*faceSize])];
00264 std::set<int> tempSet;
00265 for (int nodeNum=1; nodeNum<faceSize; ++nodeNum,tempSet.clear()) {
00266 std::set<int>& nn =
00267 nodeNeighbors[elems.getConn(elem, faces[face*faceSize+nodeNum])];
00268 std::set_intersection(elemNeighbors.begin(),
00269 elemNeighbors.end(),
00270 nn.begin(),
00271 nn.end(),
00272 std::inserter(tempSet, tempSet.begin()));
00273 elemNeighbors = tempSet;
00274 }
00275 CkAssert(elemNeighbors.size() <= 2);
00276 for (std::set<int>::iterator i = elemNeighbors.begin();
00277 i != elemNeighbors.end();
00278 ++i) {
00279 if (*i != elem) g->add(elem, *i);
00280 }
00281 }
00282 }
00283 }
00284 }
00285
00286
00287
00288
00289
00290 void FEM_Mesh_partition(const FEM_Mesh *mesh,int nchunks,int *elem2chunk, bool faceGraph)
00291 {
00292 CkThresholdTimer time("FEM Split> Building graph for metis partitioner",1.0);
00293 int nelems=mesh->nElems();
00294 if (nchunks==1) {
00295 for (int i=0;i<nelems;i++) elem2chunk[i]=0;
00296 return;
00297 }
00298 Graph g(nelems);
00299 if (!faceGraph) {
00300 mesh2graph(mesh,&g);
00301 } else {
00302 mesh2graph_face(mesh,&g);
00303 }
00304
00305 int *adjStart;
00306 int *adjList;
00307 g.toAdjList(adjStart,adjList);
00308
00309 int ecut,ncon=1;
00310 time.start("FEM Split> Calling metis partitioner");
00311 if (nchunks<8)
00312 METIS_PartGraphRecursive(&nelems, &ncon, adjStart, adjList, NULL, NULL, NULL,
00313 &nchunks, NULL, NULL, NULL, &ecut, elem2chunk);
00314 else
00315 METIS_PartGraphKway(&nelems, &ncon, adjStart, adjList, NULL, NULL, NULL,
00316 &nchunks, NULL, NULL, NULL, &ecut, elem2chunk);
00317 delete[] adjStart;
00318 delete[] adjList;
00319 }
00320