libs/ck-libs/fem/partition.C

Go to the documentation of this file.
00001 /*Charm++ Finite Element Framework:
00002 C++ implementation file
00003 
00004 This code implements exactly one routine: fem_partition.
00005 This partitions a mesh's elements into n chunks, and writes
00006 out each element's 0-based chunk number to an array.
00007 
00008 The partitioning is done using metis.
00009 
00010 Originally written by Karthik Mahesh, September 2000.
00011 */
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <assert.h>
00015 #include "fem_impl.h"
00016 #include "cktimer.h"
00017 
00018 class NList
00019 {
00020   int nn; // number of current elements
00021   int sn; // size of array n
00022   int *elts; // list of elts
00023   static int cmp(const void *v1, const void *v2);
00024  public:
00025   NList(void) { sn = 0; nn = 0; elts = 0; }
00026   void init(int _sn) { sn = _sn; nn = 0; elts = new int[sn]; }
00027   void add(int elt);
00028   int found(int elt);
00029   void sort(void) { qsort(elts, nn, sizeof(int), cmp); };
00030   int getnn(void) { return nn; }
00031   int getelt(int n) { assert(n < nn); return elts[n]; }
00032   ~NList() { delete [] elts; }
00033 };
00034 
00035 class Nodes
00036 {
00037   int nnodes;
00038   NList *elts;
00039  public:
00040   Nodes(int _nnodes);
00041   ~Nodes() { delete [] elts; }
00042   void add(int node, int elem);
00043   int nelems(int node) 
00044   {
00045     assert(node < nnodes);
00046     return elts[node].getnn();
00047   }
00048   int getelt(int node, int n)
00049   {
00050     assert(node < nnodes);
00051     return elts[node].getelt(n);
00052   }
00053 };
00054 
00055 class Graph
00056 {
00057   int nelems;
00058   NList *nbrs;
00059  public:
00060   Graph(int elems);
00061   ~Graph() { delete [] nbrs; }
00062   void add(int elem1, int elem2);
00063   int elems(int elem)
00064   {
00065     assert(elem<nelems);
00066     return nbrs[elem].getnn();
00067   }
00068   void toAdjList(int *&adjStart,int *&adjList);
00069 };
00070 
00071 int NList::cmp(const void *v1, const void *v2)
00072 {
00073   int *e1 = (int *) v1;
00074   int *e2 = (int *) v2;
00075   if(*e1==*e2) return 0;
00076   else if(*e1 < *e2) return -1;
00077   else return 1;
00078 }
00079 
00080 void NList::add(int elt) 
00081 {
00082   // see if elts is full
00083   // if yes, allocate more space, and copy existing nbrs there
00084   // delete old space
00085 
00086   if (sn <= nn) {
00087     sn *= 2;
00088     int *telts = new int[sn];
00089     for (int i=0; i<nn; i++)
00090       telts[i] = elts[i];
00091     delete[] elts;
00092     elts = telts;
00093   }
00094 
00095   // add new neighbor
00096   elts[nn++] = elt;
00097 }
00098 
00099 int NList::found(int elt)
00100 {
00101   for(int i = 0; i < nn; i++) 
00102   {
00103     if(elts[i] == elt)
00104       return 1;
00105   }
00106   return 0;
00107 }
00108 
00109 Nodes::Nodes(int _nnodes) 
00110 {
00111   nnodes = _nnodes;
00112   elts = new NList[nnodes];
00113 
00114   for(int i=0; i<nnodes; i++) {
00115     elts[i].init(10);
00116   }
00117 }
00118 
00119 void Nodes::add(int node, int elem) 
00120 {
00121   assert(node < nnodes);
00122   elts[node].add(elem);
00123 }
00124 
00125 Graph::Graph(int _nelems) 
00126 {
00127   nelems = _nelems;
00128   nbrs = new NList[nelems];
00129 
00130   for(int i=0; i<nelems; i++) 
00131   {
00132     nbrs[i].init(10);
00133   }
00134 }
00135 
00136 void Graph::add(int elem1, int elem2) 
00137 {
00138   assert(elem1 < nelems);
00139   assert(elem2 < nelems);
00140 
00141 // eliminate duplicates
00142 
00143   if(!nbrs[elem1].found(elem2)) 
00144   {
00145     nbrs[elem1].add(elem2);
00146     nbrs[elem2].add(elem1);
00147   }
00148 }
00149 
00150 
00151 void Graph::toAdjList(int *&adjStart,int *&adjList)
00152 {
00153         int e,i;
00154         adjStart=new int[nelems+1];
00155         adjStart[0]=0;
00156         for (e=0;e<nelems;e++)
00157                 adjStart[e+1]=adjStart[e]+elems(e);
00158         adjList=new int[adjStart[nelems]];
00159         int *adjOut=adjList;
00160         for (e=0;e<nelems;e++)
00161                 for (i=nbrs[e].getnn()-1;i>=0;i--)
00162                         *(adjOut++)=nbrs[e].getelt(i);
00163 }
00164 
00165 
00166 void mesh2graph(const FEM_Mesh *m, Graph *g)
00167 {
00168   Nodes nl(m->node.size());
00169 
00170   //Build an inverse mapping, from node to list of surrounding elements
00171   int globalCount=0,t,e,n;
00172   for(t=0;t<m->elem.size();t++) 
00173   if (m->elem.has(t)) {
00174     const FEM_Elem &k=m->elem[t];
00175     for(e=0;e<k.size();e++,globalCount++)
00176       for(n=0;n<k.getNodesPer();n++)
00177         nl.add(k.getConn(e,n),globalCount);
00178   }
00179   
00180   //Convert nodelists to graph:
00181   // Elements become nodes of graph; nodes become edges of graph.
00182   // Metis can partition this graph.
00183   int i, j;    
00184   for(i = 0; i < m->node.size(); i++) {
00185     int nn = nl.nelems(i);
00186     for(j = 0; j < nn; j++) {
00187       int e1 = nl.getelt(i, j);
00188       for(int k = j + 1; k < nn; k++) {
00189         int e2 = nl.getelt(i, k);
00190         g->add(e1, e2);
00191       }
00192     }
00193   }
00194 }
00195 
00196 
00197 //FIXME: Shouldn't these prototypes come from some METIS header file?
00198 typedef int idxtype;
00199 extern "C" void 
00200 METIS_PartGraphRecursive(int *, int *, int *, idxtype *, idxtype *, 
00201 int *, int *, int *, int *, int *, idxtype *);
00202 
00203 extern "C" void
00204 METIS_PartGraphKway (int* nv, int* xadj, int* adjncy, int* vwgt, int* adjwgt,
00205                        int* wgtflag, int* numflag, int* nparts, int* options,
00206                        int* edgecut, int* part);
00207 
00208 
00209 /*Partition this mesh's elements into n chunks,
00210  writing each element's 0-based chunk number to elem2chunk.
00211 */
00212 void FEM_Mesh_partition(const FEM_Mesh *mesh,int nchunks,int *elem2chunk)
00213 {
00214         CkThresholdTimer time("FEM Split> Building graph for metis partitioner",1.0);
00215         int nelems=mesh->nElems();
00216         if (nchunks==1) {//Metis can't handle this case (!)
00217                 for (int i=0;i<nelems;i++) elem2chunk[i]=0;
00218                 return;
00219         }
00220         Graph g(nelems);
00221         mesh2graph(mesh,&g);
00222         
00223         int *adjStart; /*Maps elem # -> start index in adjacency list*/
00224         int *adjList; /*Lists adjacent vertices for each element*/
00225         g.toAdjList(adjStart,adjList);
00226         int ecut,numflag=0;
00227         int wgtflag = 0; // no weights associated with elements or edges
00228         int opts[5];
00229         opts[0] = 0; //use default values
00230         time.start("FEM Split> Calling metis partitioner");
00231         if (nchunks<8) /*Metis manual says recursive version is higher-quality here*/
00232           METIS_PartGraphRecursive(&nelems, adjStart, adjList, 0, 0, &wgtflag, &numflag, 
00233                         &nchunks, opts, &ecut, elem2chunk);
00234         else /*For many chunks, Kway is supposedly faster */
00235           METIS_PartGraphKway(&nelems, adjStart, adjList, 0, 0, &wgtflag, &numflag, 
00236                         &nchunks, opts, &ecut, elem2chunk);
00237         delete[] adjStart;
00238         delete[] adjList;
00239 }

Generated on Sun Jun 29 13:29:21 2008 for Charm++ by  doxygen 1.5.1