Metis.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 1999, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** ****************************************************************** */
00020                                                                         
00021 // $Revision: 1.3 $
00022 // $Date: 2006/01/12 23:37:19 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/graph/partitioner/Metis.cpp,v $
00024                                                                         
00025                                                                         
00026 // Written: fmk 
00027 // Created: Sun Sept 15 11:47:47: 1996
00028 // Revision: A
00029 //
00030 // Description: This file contains the class definition for Metis.
00031 // Metis is a type of GraphPartitioner which uses 'METIS - Unstructured
00032 // Graph Partitioning And Sparse Matrix Ordering System', developed by
00033 // G. Karypis and V. Kumar at the University of Minnesota. The metis
00034 // files are found in metis-2.0 which were downloaded.
00035 //     This class provides the C++ interface for metis which will allow
00036 // it to fit seamlessly into our system.
00037 //
00038 // What: "@(#) Metis.C, revA"
00039 
00040 #include <Metis.h>
00041 #include <Graph.h>
00042 #include <Vertex.h>
00043 #include <VertexIter.h>
00044 
00045 /* stuff needed to get the program working on the clump & NOW machines*/
00046 #include <bool.h>
00047 
00048 //int IsWeighted;
00049 
00050 extern "C" 
00051 int PMETIS(int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *);
00052 
00053 extern "C" 
00054 int KMETIS(int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *);
00055 
00056 Metis::Metis(int numParts) 
00057 :GraphNumberer(GraphNUMBERER_TAG_Metis),
00058  myPtype(0), myMtype(0), myCoarsenTo(0), myRtype(0), myIPtype(0),
00059  defaultOptions(true), numPartitions(numParts), theRefResult(0)
00060 {
00061     
00062 }
00063 
00064 Metis::Metis(int Ptype, 
00065           int Mtype, 
00066           int coarsenTo,
00067           int Rtype, 
00068           int IPtype,
00069           int numParts)
00070 :GraphNumberer(GraphNUMBERER_TAG_Metis),
00071  myPtype(Ptype), myMtype(Mtype), myCoarsenTo(coarsenTo), myRtype(Rtype), 
00072  myIPtype(IPtype), defaultOptions(false), numPartitions(numParts), theRefResult(0)
00073 {
00074     // check the options are valid
00075     checkOptions();
00076 }    
00077 
00078     
00079 Metis::~Metis() 
00080 {
00081 
00082 }    
00083 
00084 bool
00085 Metis::setOptions(int Ptype, 
00086                   int Mtype,
00087                   int coarsenTo,
00088                   int Rtype, 
00089                   int IPtype)
00090 {
00091     myPtype=Ptype; 
00092     myMtype = Mtype; 
00093     myCoarsenTo = coarsenTo; 
00094     myRtype = Rtype; 
00095     myIPtype = IPtype; 
00096 
00097     defaultOptions = false;
00098     
00099     return checkOptions();
00100     
00101 }    
00102 
00103 
00104 // bool checkOptions(void) const
00105 //      returns true if options are o.k., false otherwise
00106 
00107 bool
00108 Metis::checkOptions(void) 
00109 {
00110 
00111     // check default not set
00112     
00113     if (defaultOptions == true)
00114         return true;
00115 
00116     
00117     // otherwise check all options for valid value
00118     bool okFlag = true;    
00119     
00120     if ((myPtype != 1) || (myPtype != 2)) {
00121         okFlag = false;
00122         opserr << "WARNING: Metis::partition ";
00123         opserr << " - Illegal Ptype " << myPtype << endln;
00124     }
00125         
00126     if ((myMtype != 1) ||  (myMtype != 2) || (myMtype != 3) || 
00127         ((myMtype != 4) || (myMtype != 5) || myMtype != 11) || 
00128         (myMtype != 21) || (myMtype != 51)) {
00129         okFlag = false;
00130         opserr << "WARNING: Metis::partition ";
00131         opserr << " - Illegal Mtype " << myMtype << endln;
00132     }
00133 
00134     if (myPtype == 1)  
00135         if ((myRtype != 1) || (myRtype != 2) || (myRtype != 3) ||
00136             (myRtype != 11) || (myRtype != 12) || (myRtype != 13) ||
00137             (myRtype != 20)) {
00138             okFlag = false;
00139             opserr << "WARNING: Metis::partition ";
00140             opserr << " - Illegal Rtype " << myRtype << endln;
00141             opserr << " for Ptype " << myPtype << endln;            
00142         }
00143     else 
00144         if (myPtype == 2)
00145             if ((myRtype != 11) || (myRtype != 12) || (myRtype != 20)) {
00146                 okFlag = false;
00147                 opserr << "WARNING: Metis::partition ";
00148                 opserr << " - Illegal Rtype " << myRtype << endln;
00149                 opserr << " for Ptype " << myPtype << endln;        
00150             }
00151     
00152     if ((myIPtype != 1) || (myIPtype != 2) || (myIPtype != 3) || 
00153         (myIPtype != 4)) {
00154         okFlag = false;
00155         opserr << "WARNING: Metis::partition ";
00156         opserr << " - Illegal IPtype " << myIPtype << endln;
00157     }       
00158         
00159     if (myCoarsenTo < 0) {
00160         okFlag = false;
00161         opserr << "WARNING: Metis::partition ";
00162         opserr << " - Illegal coarsen To " << myCoarsenTo << endln;
00163     }       
00164 
00165     if (okFlag == false)
00166         defaultOptions = true;
00167     
00168     return okFlag;
00169 
00170 }
00171 
00172 
00173 bool 
00174 Metis::setDefaultOptions(void)
00175 {
00176     defaultOptions = true;
00177     return true;
00178 }
00179 
00180 
00181 // int partition(Graph &theGraph, int numPart)
00182 //      Method to partition the graph. It first creates the arrays needed
00183 //      by the metis lib and then invokes a function from the metis lib to
00184 //      partition the graph. The solors of the vertices of the graph are
00185 //      set to colors 0 through numPart-1 to indicate which partition the
00186 //      vrtices are in. Returns -1 if options are not set, -2 if metis failed.
00187 
00188 int
00189 Metis::partition(Graph &theGraph, int numPart)
00190 {
00191   if (theGraph.getNumVertex() == numPart) {
00192     Vertex *vertex;
00193     int current = 1;
00194     VertexIter &theVertices = theGraph.getVertices();
00195     while ((vertex = theVertices()) != 0)
00196            vertex->setColor(current++);
00197     
00198     return 0;
00199   }
00200 
00201     // first we check that the options are valid
00202     if (checkOptions() == false)
00203         return -1;
00204     
00205     // now we get room for the data structures metis needs
00206 
00207     int numVertex = theGraph.getNumVertex();
00208     int numEdge = theGraph.getNumEdge();
00209 
00210     int *options = new int [5];
00211     int *partition = new int [numVertex+1];    
00212     int *xadj = new int [numVertex+2];
00213     int *adjncy = new int [2*numEdge];
00214     int *vwgts = 0;
00215     int *ewgts = 0;
00216     int numbering = 0;
00217     int weightflag = 0; // no weights on our graphs yet
00218 
00219     if (START_VERTEX_NUM == 0)
00220         numbering = 0;  
00221     else if (START_VERTEX_NUM == 1)
00222         numbering = 1;
00223     else {
00224         opserr << "WARNING Metis::partition - No partitioning done";
00225         opserr << " vertex numbering must start at 0 or 1\n";
00226         return (-2);
00227     }
00228     int edgecut;
00229     
00230     if ((options == 0) || (partition == 0) || (xadj == 0) || (adjncy == 0)) {
00231         opserr << "WARNING Metis::partition - No partitioning done";
00232         opserr << " as ran out of memory\n";
00233         return (-2);
00234     }
00235 
00236 
00237     // we build these data structures
00238     
00239     int indexEdge = 0;
00240     xadj[0] = 0;
00241 
00242     Vertex *vertexPtr;
00243     for (int vertex =0; vertex<numVertex; vertex++) {
00244         vertexPtr = theGraph.getVertexPtr(vertex+START_VERTEX_NUM);
00245         
00246         // check we don't have an invalid vertex numbering scheme
00247         // if so WARNING message, clean up and return -2
00248 
00249         if (vertexPtr == 0) {
00250             opserr << "WARNING Metis::partition - No partitioning done";
00251             opserr << " Metis requires consequtive Vertex Numbering\n";
00252             
00253             delete [] options;
00254             delete [] partition;
00255             delete [] xadj;
00256             delete [] adjncy;
00257             
00258             return -2;
00259         }
00260         
00261         const ID&adjacency = vertexPtr->getAdjacency();
00262         int degree = adjacency.Size();
00263         for (int i=0; i<degree; i++) {
00264             adjncy[indexEdge++] = adjacency(i)-START_VERTEX_NUM;
00265         }
00266         
00267         xadj[vertex+1] = indexEdge;
00268     }
00269 
00270     if (defaultOptions == true) 
00271         options[0] = 0;
00272     else {
00273         options[0] =1;
00274         options[1] = myCoarsenTo;
00275         options[2] = myMtype;
00276         options[3] = myIPtype;
00277         options[4] = myRtype;
00278     }
00279     
00280     // we now the metis routines
00281 
00282     if (myPtype == 1)
00283         PMETIS(&numVertex, xadj, adjncy, vwgts, ewgts, &weightflag, &numPart,
00284                options, &numbering, &edgecut, partition);
00285     else                
00286         KMETIS(&numVertex, xadj, adjncy, vwgts, ewgts, &weightflag, &numPart,
00287                options, &numbering, &edgecut, partition);
00288 
00289     // we set the vertex colors to correspond to the partitioned scheme
00290     for (int vert =0; vert<numVertex; vert++) {
00291         vertexPtr = theGraph.getVertexPtr(vert+START_VERTEX_NUM);
00292         vertexPtr->setColor(partition[vert]+1); // start colors at 1
00293     }
00294 
00295     // clean up the space and return
00296     
00297     delete [] options;
00298     delete [] partition;
00299     delete [] xadj;
00300     delete [] adjncy;
00301 
00302     return 0;
00303 }
00304 
00305 
00306 
00307 
00308 
00309 
00310 const ID &
00311 Metis::number(Graph &theGraph, int lastVertex)
00312 {
00313     // first we check that the options are valid
00314     // first check our size, if not same make new
00315     int numVertex = theGraph.getNumVertex();
00316     // delete the old
00317     if (theRefResult != 0)
00318       delete theRefResult;
00319         
00320     theRefResult = new ID(numVertex);
00321 
00322     if (theRefResult == 0) {
00323       opserr << "ERROR:  Metis::number - Out of Memory\n";
00324       theRefResult = new ID(0);
00325       return *theRefResult;
00326     }
00327 
00328     if (checkOptions() == false) {
00329       opserr << "ERROR:  Metis::number - chek options failed\n";
00330       return *theRefResult;
00331     }
00332     
00333     // now we get room for the data structures metis needs
00334     int numEdge = theGraph.getNumEdge();
00335 
00336     int *options = new int [5];
00337     int *partition = new int [numVertex+1];    
00338     int *xadj = new int [numVertex+2];
00339     int *adjncy = new int [2*numEdge];
00340     int *vwgts = 0;
00341     int *ewgts = 0;
00342     int numbering = 0;
00343     int weightflag = 0; // no weights on our graphs yet
00344 
00345     if (START_VERTEX_NUM == 0)
00346         numbering = 0;  
00347     else if (START_VERTEX_NUM == 1)
00348         numbering = 1;
00349     else {
00350         opserr << "WARNING Metis::partition - No partitioning done";
00351         opserr << " vertex numbering must start at 0 or 1\n";
00352         return *theRefResult;
00353     }
00354     int edgecut;
00355     
00356     if ((options == 0) || (partition == 0) || (xadj == 0) || (adjncy == 0)) {
00357         opserr << "WARNING Metis::partition - No partitioning done";
00358         opserr << " as ran out of memory\n";
00359         return *theRefResult;
00360     }
00361 
00362 
00363     // we build these data structures
00364     
00365     int indexEdge = 0;
00366     xadj[0] = 0;
00367 
00368     Vertex *vertexPtr;
00369     for (int vertex =0; vertex<numVertex; vertex++) {
00370         vertexPtr = theGraph.getVertexPtr(vertex+START_VERTEX_NUM);
00371         
00372         // check we don't have an invalid vertex numbering scheme
00373         // if so WARNING message, clean up and return -2
00374 
00375         if (vertexPtr == 0) {
00376             opserr << "WARNING Metis::partition - No partitioning done";
00377             opserr << " Metis requires consequtive Vertex Numbering\n";
00378             
00379             delete [] options;
00380             delete [] partition;
00381             delete [] xadj;
00382             delete [] adjncy;
00383             
00384             return *theRefResult;
00385         }
00386         
00387         const ID&adjacency = vertexPtr->getAdjacency();
00388         int degree = adjacency.Size();
00389         for (int i=0; i<degree; i++) {
00390             adjncy[indexEdge++] = adjacency(i)-START_VERTEX_NUM;
00391         }
00392         
00393         xadj[vertex+1] = indexEdge;
00394     }
00395 
00396 
00397     if (defaultOptions == true) 
00398         options[0] = 0;
00399     else {
00400         options[0] =1;
00401         options[1] = myCoarsenTo;
00402         options[2] = myMtype;
00403         options[3] = myIPtype;
00404         options[4] = myRtype;
00405     }
00406     
00407     
00408     // we now the metis routines
00409 
00410     if (myPtype == 1)
00411 
00412       PMETIS(&numVertex, xadj, adjncy, vwgts, ewgts, &weightflag, 
00413              &numPartitions, options, &numbering, &edgecut, partition);
00414     else                
00415       KMETIS(&numVertex, xadj, adjncy, vwgts, ewgts, &weightflag, 
00416              &numPartitions, options, &numbering, &edgecut, partition);
00417 
00418 opserr << "Metis::number -2\n";
00419     // we assign numbers now based on the partitions returned.
00420     // each vertex in partion i is assigned a number less than
00421     // thos in partion i+1: NOTE WE DON'T CARE WHAT THE NUMBERING IS
00422     // WITHIN A PARTITION
00423     int count = 0;
00424     for (int i=0; i<numPartitions; i++) {
00425       for (int vert=0; vert<numVertex; vert++) {
00426         if (partition[vert] == i) {
00427           vertexPtr = theGraph.getVertexPtr(vert+START_VERTEX_NUM);
00428           vertexPtr->setTmp(count+1);
00429           (*theRefResult)(count) = vertexPtr->getRef();
00430           count++;
00431         }
00432       }
00433     }
00434 opserr << "Metis::number -3\n";
00435     // clean up the space and return
00436     delete [] options;
00437     delete [] partition;
00438     delete [] xadj;
00439     delete [] adjncy;
00440 opserr << "Metis::number -4\n";    
00441     return *theRefResult;
00442 }
00443 
00444 
00445 const ID &
00446 Metis::number(Graph &theGraph, const ID &lastVertices)
00447 {
00448   return this->number(theGraph);
00449 }
00450 
00451 int 
00452 Metis::sendSelf(int cTag, Channel &theChannel)
00453 {
00454   return 0;
00455 }
00456 
00457 int 
00458 Metis::recvSelf(int cTag, Channel &theChannel, FEM_ObjectBroker &theBroker)
00459 {
00460   return 0;
00461 }
00462 

Generated on Mon Oct 23 15:05:12 2006 for OpenSees by doxygen 1.5.0