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