ParallelNumberer.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.1 $
00022 // $Date: 2005/11/29 21:55:32 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/analysis/numberer/ParallelNumberer.cpp,v $                                                                        
00024 
00025 // Written: fmk 
00026 // Revision: A
00027 //
00028 // Description: This file contains the implementation for ParallelNumberer.
00029 //
00030 // What: "@(#) ParallelNumberer.C, revA"
00031 
00032 #include <ParallelNumberer.h>
00033 #include <AnalysisModel.h>
00034 
00035 #include <Domain.h>
00036 #include <ID.h>
00037 #include <Channel.h>
00038 #include <FEM_ObjectBroker.h>
00039 #include <Graph.h>
00040 #include <Vertex.h>
00041 #include <VertexIter.h>
00042 #include <DOF_Group.h>
00043 #include <GraphNumberer.h>
00044 #include <FE_Element.h>
00045 #include <FE_EleIter.h>
00046 
00047 ParallelNumberer::ParallelNumberer(int dTag, int numSub, Channel **theC) 
00048   :DOF_Numberer(NUMBERER_TAG_ParallelNumberer), 
00049    processID(dTag), numChannels(numSub)
00050 
00051 {
00052   theChannels = new Channel *[numSub];
00053   for (int i=0; i<numSub; i++)
00054     theChannels[i] = theC[i];
00055 }
00056 
00057 ParallelNumberer::ParallelNumberer() 
00058   :DOF_Numberer(NUMBERER_TAG_ParallelNumberer), theNumberer(0),
00059    processID(0), numChannels(0), theChannels(0)
00060 {
00061   
00062 }
00063 
00064 
00065 ParallelNumberer::ParallelNumberer(GraphNumberer &theGraphNumberer) 
00066   :DOF_Numberer(NUMBERER_TAG_ParallelNumberer), theNumberer(&theGraphNumberer),
00067    processID(0), numChannels(0), theChannels(0)
00068 {
00069   
00070 }
00071 
00072 
00073 ParallelNumberer::~ParallelNumberer() 
00074 {
00075   if (theChannels != 0)
00076     delete [] theChannels;
00077 
00078   if (theNumberer != 0)
00079     delete theNumberer;
00080 }
00081 
00082 
00083 int
00084 ParallelNumberer::setProcessID(int dTag) 
00085 {
00086   processID = dTag;
00087   return 0;
00088 }
00089 
00090 int
00091 ParallelNumberer::setChannels(int nChannels, Channel **theC)
00092 {
00093   numChannels = nChannels;
00094 
00095   if (theChannels != 0)
00096     delete [] theChannels;
00097 
00098   theChannels = new Channel *[numChannels];
00099   for (int i=0; i<numChannels; i++)
00100     theChannels[i] = theC[i];
00101 
00102   return 0;
00103 }
00104 
00105 
00106 // int numberDOF(void)
00107 // The ParalellNumberer sitting on P0, collects each partition graph from P1 through Pn-1, 
00108 // merges them into 1 large graph, & then numbers this graph. The ParallelNumberers sitting 
00109 // on P1 through Pn-1 then receive the mapping info for the dof tag and dof numbering from P0.
00110 
00111 int
00112 ParallelNumberer::numberDOF(int lastDOF)
00113 {
00114   int result = 0;
00115 
00116   // get a pointer to the model & check its not null
00117   AnalysisModel *theModel = this->getAnalysisModelPtr();
00118   Domain *theDomain = 0;
00119   if (theModel != 0) theDomain = theModel->getDomainPtr();
00120   
00121   if (theModel == 0 || theDomain == 0) {
00122     opserr << "WARNING ParallelNumberer::numberDOF(int) -";
00123     opserr << " - no AnalysisModel - has setLinks() been invoked?\n";
00124     return -1;
00125   }
00126   
00127   if (lastDOF != -1) {
00128     opserr << "WARNING ParallelNumberer::numberDOF(int lastDOF):";
00129     opserr << " does not use the lastDOF as requested\n";
00130   }
00131 
00132   Graph &theGraph = theModel->getDOFGroupGraph();
00133 
00134   // if subdomain, collect graph, send it off, get 
00135   // ID back containing dof tags & start id numbers.
00136   if (processID != 0) {
00137 
00138     Channel *theChannel = theChannels[0];
00139     int numVertex = theGraph.getNumVertex();
00140 
00141     /*
00142     static ID test(2); test(0) = processID; test(1) = 25;
00143     theChannel->recvID(0, 0, test);
00144     */
00145 
00146     theGraph.sendSelf(0, *theChannel);
00147 
00148     // recv iD
00149     ID theID(2*numVertex);
00150     theChannel->recvID(0, 0, theID);
00151 
00152     // set vertex numbering based on ID received
00153     for (int i=0; i<numVertex; i ++) {
00154       int vertexTag = theID(i);
00155       int startID = theID(i+numVertex);
00156       //      Vertex *vertexPtr = theGraph.getVertexPtr(vertexTag);
00157       int dofTag = vertexTag;
00158       DOF_Group *dofPtr;        
00159       dofPtr = theModel->getDOF_GroupPtr(dofTag);
00160       if (dofPtr == 0) {
00161         opserr << "WARNING ParallelNumberer::numberDOF - ";
00162         opserr << "DOF_Group " << dofTag << "not in AnalysisModel!\n";
00163         result = -4;
00164       } else {
00165         const ID &theDOFID = dofPtr->getID();
00166         //      opserr << "P: " << processID << " dofTag: " << dofTag << " " << "start: " << startID << " " << theDOFID;
00167         int idSize = theDOFID.Size();
00168         for (int j=0; j<idSize; j++)
00169           if (theDOFID(j) == -2 || theDOFID(j) == -3) dofPtr->setID(j, startID++);
00170       }
00171       const ID &theDOFID = dofPtr->getID();
00172     }
00173 
00174     theChannel->sendID(0, 0, theID);
00175   } 
00176   
00177   // if main domain, collect graphs from all subdomains,
00178   // merge into 1, number this one, send to subdomains the
00179   // id containing dof tags & start id's.
00180   else {
00181 
00182     // for P0 domain determine original vertex and ref tags
00183     int numVertex = theGraph.getNumVertex(); 
00184     int numVertexP0 = numVertex;
00185 
00186     ID vertexTags(numVertex);
00187     ID vertexRefs(numVertex);
00188     Vertex *vertexPtr;
00189     int loc = 0;
00190     VertexIter &theVertices = theGraph.getVertices();
00191     while ((vertexPtr = theVertices()) != 0) {
00192       vertexTags[loc] = vertexPtr->getTag();
00193       vertexRefs[loc] = vertexPtr->getRef();
00194       loc++;
00195     }
00196     
00197     ID **theSubdomainIDs = new ID *[numChannels];
00198     FEM_ObjectBroker theBroker;
00199 
00200     // for each subdomain we receive graph, create an ID (to store
00201     // subdomain graph to merged graph vertex mapping and the final
00202     // subdoain graph vertex to startDOF mapping) and finally merge the
00203     // subdomain graph
00204 
00205     for (int j=0; j<numChannels; j++) {
00206       Channel *theChannel = theChannels[j];
00207       Graph *theSubGraph = new Graph();
00208 
00209       /*
00210       static ID test(2); test(0) = processID; test(1) = 25;
00211       theChannel->sendID(0, 0, test);
00212       */
00213 
00214       theSubGraph->recvSelf(0, *theChannel, theBroker);
00215 
00216       theSubdomainIDs[j] = new ID(theSubGraph->getNumVertex()*2);
00217 
00218       this->mergeSubGraph(theGraph, *theSubGraph, vertexTags, vertexRefs, *theSubdomainIDs[j]);
00219       
00220       delete theSubGraph;
00221     }
00222     
00223     // we use graph numberer if one was provided in constructor,
00224     // otherwise we number based on subdomains (all in subdomain 1 numbered first, 
00225     // then  those in 2 not in 1 and so on till done.
00226     //    GraphNumberer *theNumberer = this->getGraphNumbererPtr();
00227 
00228     ID *theOrderedRefs = new ID(theGraph.getNumVertex());
00229 
00230     if (theNumberer != 0) {
00231 
00232       // use the supplied graph numberer to number the merged graph
00233       *theOrderedRefs = theNumberer->number(theGraph, lastDOF);     
00234 
00235     } else {
00236 
00237       // assign numbers based on the subdomains
00238 
00239       int loc = 0;
00240       for (int l=0; l<numChannels; l++) {
00241         const ID &theSubdomain = *theSubdomainIDs[l];
00242         int numVertexSubdomain = theSubdomain.Size()/2;
00243 
00244         for (int i=0; i<numVertexSubdomain; i++) {
00245           int vertexTagMerged = theSubdomain(i+numVertexSubdomain);
00246           //  int refTag = vertexRefs[vertexTags.getLocation(vertexTagMerged)];
00247           if (theOrderedRefs->getLocation(vertexTagMerged) == -1)
00248             (*theOrderedRefs)[loc++] = vertexTagMerged;
00249         }
00250       }
00251 
00252       // now order those not yet ordered in p0
00253       for (int j=0; j<numVertexP0; j++) {
00254         int refTagP0 = vertexTags[j];
00255         if (theOrderedRefs->getLocation(refTagP0) == -1)
00256           (*theOrderedRefs)[loc++] = refTagP0;
00257       } 
00258 
00259     }
00260 
00261 
00262     int count = 0;
00263     for (int i=0; i<theOrderedRefs->Size(); i++) {
00264       int vertexTag = (*theOrderedRefs)(i);
00265       //      int vertexTag = vertexTags[vertexRefs.getLocation(tag)];
00266       Vertex *vertexPtr = theGraph.getVertexPtr(vertexTag);
00267       int numDOF= vertexPtr->getColor();
00268       vertexPtr->setTmp(count);
00269       count += numDOF;
00270     }
00271 
00272     if (theNumberer == 0)
00273       delete theOrderedRefs;
00274 
00275     // number own dof's
00276     for (int i=0; i<numVertexP0; i++  ) {
00277       int vertexTag = vertexTags(i);
00278       Vertex *vertexPtr = theGraph.getVertexPtr(vertexTag);
00279 
00280       int startID = vertexPtr->getTmp();
00281       int dofTag = vertexTag;
00282       DOF_Group *dofPtr;        
00283       dofPtr = theModel->getDOF_GroupPtr(dofTag);
00284       if (dofPtr == 0) {
00285         opserr << "WARNING ParallelNumberer::numberDOF - ";
00286         opserr << "DOF_Group (P0) " << dofTag << "not in AnalysisModel!\n";
00287         result = -4;
00288       } else {
00289         const ID &theDOFID = dofPtr->getID();
00290         int idSize = theDOFID.Size();
00291         for (int j=0; j<idSize; j++)
00292           if (theDOFID(j) == -2 || theDOFID(j) == -3) dofPtr->setID(j, startID++);
00293       }
00294     }
00295 
00296     // now given the ordered refs we determine the mapping for each subdomain
00297     // and send the id with the information back to the subdomain, which it uses to order
00298     // it's own graph
00299     for (int k=0; k<numChannels; k++) {
00300       Channel *theChannel = theChannels[k];
00301       ID &theSubdomain = *theSubdomainIDs[k];
00302       int numVertexSubdomain = theSubdomain.Size()/2;
00303 
00304       for (int i=0; i<numVertexSubdomain; i++) {
00305         int vertexTagMerged = theSubdomain[numVertexSubdomain+i];
00306         Vertex *vertexPtr = theGraph.getVertexPtr(vertexTagMerged);
00307         int startDOF = vertexPtr->getTmp();
00308         theSubdomain[i+numVertexSubdomain] = startDOF;
00309       }
00310 
00311       theChannel->sendID(0, 0, theSubdomain);
00312       theChannel->recvID(0, 0, theSubdomain);
00313       delete theSubdomainIDs[k];
00314     }      
00315     delete [] theSubdomainIDs;
00316   }
00317 
00318   // iterate through the FE_Element getting them to set their IDs
00319   FE_EleIter &theEle = theModel->getFEs();
00320   FE_Element *elePtr;
00321   while ((elePtr = theEle()) != 0)
00322     elePtr->setID();
00323   
00324   return result;
00325 }
00326 
00327 
00328 int
00329 ParallelNumberer::mergeSubGraph(Graph &theGraph, Graph &theSubGraph, ID &vertexTags, ID &vertexRefs, ID &theSubdomainMap)
00330 {  
00331   // for each vertex in the SubGraph we see if a vertex exists in the Graph which has the same
00332   // reference tag (Reference tag in the AnalysisModel graph is the node tag) .. if so this will be 
00333   // the new vertex tag for SubGraph vertex in new graph, otherwise we assign it some new vertex tag,
00334   // create a vertex for this new vertex tag & add it to the graph
00335 
00336   Vertex *subVertexPtr;
00337   VertexIter &theSubGraphIter1 = theSubGraph.getVertices();
00338   int count =0;
00339   int numVertex = theGraph.getNumVertex();
00340   int numVertexSub = theSubGraph.getNumVertex();
00341 
00342   while ((subVertexPtr = theSubGraphIter1()) != 0) {
00343     int vertexTagSub = subVertexPtr->getTag();
00344     int vertexTagRef = subVertexPtr->getRef();
00345     int loc = vertexRefs.getLocation(vertexTagRef);
00346 
00347     int vertexTagMerged;
00348     if (loc < 0) {
00349       // if not already in, we will be creating a new vertex
00350       vertexTagMerged = theGraph.getFreeTag();
00351       vertexTags[numVertex] = vertexTagMerged;
00352       vertexRefs[numVertex] = vertexTagRef;
00353       Vertex *newVertex = new Vertex(vertexTagMerged, vertexTagRef, subVertexPtr->getWeight(), subVertexPtr->getColor());
00354 
00355       theGraph.addVertex(newVertex);
00356       numVertex++;
00357     } else
00358       vertexTagMerged = vertexTags[loc];
00359 
00360     // use the subgraphs ID to hold the mapping of vertex numbers between merged and original
00361     theSubdomainMap[count] = vertexTagSub;
00362     theSubdomainMap[count+numVertexSub] = vertexTagMerged;
00363     count++;
00364   }
00365 
00366   // for each vertex in subgraph, we add it's adjacenecy into the merged graph
00367   VertexIter &theSubGraphIter2 = theSubGraph.getVertices();
00368   while ((subVertexPtr = theSubGraphIter2()) != 0) {
00369     int vertexTagSub = subVertexPtr->getTag();
00370     int loc = theSubdomainMap.getLocation(vertexTagSub);
00371     int vertexTagMerged = theSubdomainMap[loc+numVertexSub];
00372 
00373     const ID &adjacency = subVertexPtr->getAdjacency();
00374 
00375     for (int i=0; i<adjacency.Size(); i++) {
00376       int vertexTagSubAdjacent = adjacency(i);
00377       int loc = theSubdomainMap.getLocation(vertexTagSubAdjacent);
00378       int vertexTagMergedAdjacent = theSubdomainMap[loc+numVertexSub];      
00379       theGraph.addEdge(vertexTagMerged, vertexTagMergedAdjacent);
00380     }
00381   }
00382 
00383 
00384   return 0;
00385 }
00386 
00387 
00388 int
00389 ParallelNumberer::sendSelf(int cTag, Channel &theChannel)
00390 {
00391   int sendID =0;
00392 
00393   // if P0 check if already sent. If already sent use old processID; if not allocate a new process 
00394   // id for remote part of object, enlarge channel * to hold a channel * for this remote object.
00395 
00396   // if not P0, send current processID
00397 
00398   if (processID == 0) {
00399 
00400     // check if already using this object
00401     bool found = false;
00402     for (int i=0; i<numChannels; i++)
00403       if (theChannels[i] == &theChannel) {
00404         sendID = i+1;
00405         found = true;
00406       }
00407 
00408     // if new object, enlarge Channel pointers to hold new channel * & allocate new ID
00409     if (found == false) {
00410       int nextNumChannels = numChannels + 1;
00411       Channel **nextChannels = new Channel *[nextNumChannels];
00412       if (nextNumChannels == 0) {
00413         opserr << "ParalellNumberer::sendSelf() - failed to allocate channel array of size: " << 
00414           nextNumChannels << endln;
00415         return -1;
00416       }
00417       for (int i=0; i<numChannels; i++)
00418         nextChannels[i] = theChannels[i];
00419       nextChannels[numChannels] = &theChannel;
00420       
00421       numChannels = nextNumChannels;
00422       
00423       if (theChannels != 0)
00424         delete [] theChannels;
00425       
00426       theChannels = nextChannels;
00427       
00428       // allocate new processID for remote object
00429       sendID = numChannels;
00430     }
00431 
00432   } else 
00433     sendID = processID;
00434 
00435 
00436   // send remotes processID
00437   ID idData(1);
00438   idData(0) = sendID;
00439   
00440   int res = theChannel.sendID(0, cTag, idData);
00441   if (res < 0) {
00442     opserr <<"WARNING DistributedSparseGenColLinSOE::sendSelf() - failed to send data\n";
00443     return -1;
00444   }
00445 
00446   return 0;
00447 }
00448 
00449 int
00450 ParallelNumberer::recvSelf(int cTag, 
00451                         Channel &theChannel, 
00452                         FEM_ObjectBroker &theBroker)
00453 {
00454   ID idData(1);
00455   int res = theChannel.recvID(0, cTag, idData);
00456   if (res < 0) {
00457     opserr <<"WARNING Parallel::recvSelf() - failed to send data\n";
00458     return -1;
00459   }           
00460   processID = idData(0);
00461 
00462   numChannels = 1;
00463   theChannels = new Channel *[1];
00464   theChannels[0] = &theChannel;
00465 
00466   return 0;
00467 }
00468 
00469 
00470 int
00471 ParallelNumberer::numberDOF(ID &lastDOFs)
00472 {
00473 
00474   int result = 0;
00475   
00476   // get a pointer to the model & check its not null
00477   AnalysisModel *theModel = this->getAnalysisModelPtr();
00478   Domain *theDomain = 0;
00479   if (theModel != 0) theDomain = theModel->getDomainPtr();
00480   
00481   if (theModel == 0 || theDomain == 0) {
00482     opserr << "WARNING ParallelNumberer::numberDOF(int) -";
00483     opserr << " - no AnalysisModel - has setLinks() been invoked?\n";
00484     return -1;
00485   }
00486   
00487   Graph &theGraph = theModel->getDOFGroupGraph();
00488   
00489   // if subdomain, collect graph, send it off, get 
00490   // ID back containing dof tags & start id numbers.
00491   if (processID != 0) {
00492     Channel *theChannel = theChannels[0];
00493     int numVertex = theGraph.getNumVertex();
00494     theGraph.sendSelf(0, *theChannel);
00495     ID theID(2*numVertex);
00496     theChannel->recvID(0, 0, theID);
00497     for (int i=0; i<numVertex; i += 2) {
00498       int dofTag = theID(i);
00499       int startID = theID(i+1);
00500       DOF_Group *dofPtr;        
00501       dofPtr = theModel->getDOF_GroupPtr(dofTag);
00502       if (dofPtr == 0) {
00503         opserr << "WARNING ParallelNumberer::numberDOF - ";
00504         opserr << "DOF_Group " << dofTag << "not in AnalysisModel!\n";
00505         result = -4;
00506       } else {
00507         const ID &theID = dofPtr->getID();
00508         int idSize = theID.Size();
00509         for (int j=0; j<idSize; j++)
00510           if (theID(j) == -2) dofPtr->setID(j, startID++);
00511       }
00512     }
00513   } 
00514   
00515   // if main domain, collect graphs from all subdomains,
00516   // merge into 1, number this one, send to subdomains the
00517   // id containing dof tags & start id's.
00518   else {
00519     
00520     // determine original vertex and ref tags
00521     int numVertex = theGraph.getNumVertex();
00522     ID vertexTags(numVertex);
00523     ID vertexRefs(numVertex);
00524     Vertex *vertexPtr;
00525     int loc = 0;
00526     VertexIter &theVertices = theGraph.getVertices();
00527     while ((vertexPtr = theVertices()) != 0) {
00528       vertexTags[loc] = vertexPtr->getTag();
00529       vertexRefs[loc] = vertexPtr->getRef();
00530       loc++;
00531     }
00532     
00533     ID **theSubdomainIDs = new ID *[numChannels];
00534     FEM_ObjectBroker theBroker;
00535 
00536     // merge all subdomain graphs
00537     for (int j=0; j<numChannels; j++) {
00538       Channel *theChannel = theChannels[j];
00539       Graph theSubGraph;
00540       theSubGraph.recvSelf(0, *theChannel, theBroker);
00541       theSubdomainIDs[j] = new ID(theSubGraph.getNumVertex()*2);
00542       this->mergeSubGraph(theGraph, theSubGraph, vertexTags, vertexRefs, *theSubdomainIDs[j]);
00543     }
00544 
00545     // number the merged graph
00546     //    result =  this->DOF_Numberer::number(theGraph);
00547 
00548     // send results of numbered back to subdomains
00549     for (int k=0; k<numChannels; k++) {
00550       Channel *theChannel = theChannels[k];
00551       // this->determineSubIDs
00552       theChannel->sendID(0, 0, *theSubdomainIDs[k]);
00553       delete theSubdomainIDs[k];
00554     }      
00555     delete [] theSubdomainIDs;
00556     
00557     // number own dof's
00558   }
00559 
00560   return result;
00561 }

Generated on Mon Oct 23 15:04:59 2006 for OpenSees by doxygen 1.5.0