DistributedBandGenLinSOE.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/12/06 22:02:08 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/system_of_eqn/linearSOE/bandGEN/DistributedBandGenLinSOE.cpp,v $
00024                                                                         
00025 // Written: fmk 
00026 //
00027 // Description: This file contains the implementation for BandGenLinSOE
00028 
00029 
00030 #include <DistributedBandGenLinSOE.h>
00031 #include <BandGenLinSolver.h>
00032 #include <Matrix.h>
00033 #include <Graph.h>
00034 #include <Vertex.h>
00035 #include <VertexIter.h>
00036 #include <f2c.h>
00037 #include <math.h>
00038 #include <Channel.h>
00039 #include <FEM_ObjectBroker.h>
00040 
00041 DistributedBandGenLinSOE::DistributedBandGenLinSOE(BandGenLinSolver &theSolvr)
00042   :BandGenLinSOE(theSolvr, LinSOE_TAGS_DistributedBandGenLinSOE), 
00043    processID(0), numChannels(0), theChannels(0), localCol(0), workArea(0), sizeWork(0), myB(0), myVectB(0)
00044 {
00045     theSolvr.setLinearSOE(*this);
00046 }
00047 
00048 
00049 DistributedBandGenLinSOE::~DistributedBandGenLinSOE()
00050 {
00051   if (theChannels != 0)
00052     delete [] theChannels;
00053 
00054   if (localCol != 0)
00055     for (int i=0; i<numChannels; i++)
00056       if (localCol[i] != 0)
00057         delete localCol[i];
00058   delete [] localCol;
00059 
00060   if (workArea != 0)
00061     delete [] workArea;
00062 
00063   if (myVectB != 0)
00064     delete myVectB;
00065 
00066   if (myB == 0)
00067     delete [] myB;
00068 }
00069 
00070 
00071 int 
00072 DistributedBandGenLinSOE::setSize(Graph &theGraph)
00073 {
00074   int result = 0;
00075   int oldSize = size;
00076   int maxNumSubVertex = 0;
00077   // if subprocess, collect graph, send it off, 
00078   // vector back containing size of system, etc.
00079   if (processID != 0) {
00080     Channel *theChannel = theChannels[0];
00081     theGraph.sendSelf(0, *theChannel);
00082     
00083     static ID data(3);
00084     theChannel->recvID(0, 0, data);
00085     size = data(0);
00086     numSubD = data(1);
00087     numSuperD = data(2);
00088 
00089     ID *subMap = new ID(theGraph.getNumVertex());
00090     localCol[0] = subMap;
00091     Vertex *vertex;
00092     VertexIter &theSubVertices = theGraph.getVertices();
00093     int cnt = 0;
00094     while((vertex = theSubVertices()) != 0) 
00095       (*subMap)(cnt++) = vertex->getTag();
00096 
00097     theChannel->sendID(0, 0, *subMap);
00098   } 
00099   
00100   // if main domain, collect graphs from all subdomains,
00101   // merge into 1, number this one, send to subdomains the
00102   // id containing dof tags & start id's.
00103   else {
00104 
00105     // from each distributed soe recv it's graph
00106     // and merge them into master graph
00107 
00108     FEM_ObjectBroker theBroker;
00109     for (int j=0; j<numChannels; j++) {
00110       Channel *theChannel = theChannels[j];
00111       Graph theSubGraph;
00112       theSubGraph.recvSelf(0, *theChannel, theBroker);
00113       theGraph.merge(theSubGraph);
00114 
00115       int numSubVertex = theSubGraph.getNumVertex();
00116       ID *subMap = new ID(numSubVertex);
00117       localCol[j] = subMap;
00118       if (numSubVertex > maxNumSubVertex)
00119         maxNumSubVertex = numSubVertex;
00120     }
00121 
00122     size = theGraph.getNumVertex();
00123 
00124     //opserr << "\n\n\n**********************************************\n"; 
00125     //theGraph.Print(opserr); 
00126     //opserr << "\n**********************************************\n\n\n"; 
00127     //
00128     // determine the number of superdiagonals and subdiagonals
00129     //
00130 
00131     numSubD = 0;
00132     numSuperD = 0;
00133 
00134     Vertex *vertexPtr;
00135     VertexIter &theVertices = theGraph.getVertices();
00136     
00137     while ((vertexPtr = theVertices()) != 0) {
00138       int vertexNum = vertexPtr->getTag();
00139       const ID &theAdjacency = vertexPtr->getAdjacency();
00140       for (int i=0; i<theAdjacency.Size(); i++) {
00141         int otherNum = theAdjacency(i);
00142         int diff = vertexNum - otherNum;
00143         if (diff > 0) {
00144           if (diff > numSuperD)
00145             numSuperD = diff;
00146         } else 
00147           if (diff < numSubD)
00148             numSubD = diff;
00149       }
00150     }
00151     numSubD *= -1;
00152     
00153     static ID data(3);
00154     data(0) = size;
00155     data(1) = numSubD;
00156     data(2) = numSuperD;
00157 
00158     // to each distributed soe send the size data
00159     // and merge them into master graph
00160 
00161     for (int j=0; j<numChannels; j++) {
00162       Channel *theChannel = theChannels[j];
00163       theChannel->sendID(0, 0, data);
00164 
00165       ID *subMap = localCol[j];
00166       theChannel->recvID(0, 0, *subMap);
00167     }    
00168   }
00169 
00170   int numCols = theGraph.getNumVertex();
00171 
00172   if (processID != 0) {
00173     ID &globalMap = *(localCol[0]);
00174     ID *localMap = new ID(size);
00175   
00176     localMap->Zero();
00177     for (int k=0; k< globalMap.Size(); k++)
00178       (*localMap)(globalMap(k)) = k; 
00179     delete localCol[0];
00180     localCol[0] = localMap;
00181   }
00182 
00183 
00184    int newSize;
00185    if (processID != 0)
00186         newSize = numCols * (2*numSubD + numSuperD + 1);
00187    else
00188         newSize = size * (2*numSubD + numSuperD + 1);
00189 
00190    // newSize = size * (2*numSubD + numSuperD + 1);
00191 
00192   if (newSize != Asize) { // we have to get another space for A
00193 
00194     if (processID == 0) {
00195       if (workArea != 0)
00196         delete [] workArea;
00197 
00198       workArea = new double [newSize];
00199       sizeWork = newSize;
00200     }
00201     sizeWork = numCols * (2*numSubD + numSuperD +1);
00202 
00203     if (A != 0) 
00204       delete [] A;
00205 
00206     A = new double[newSize];
00207     
00208     if (A == 0) {
00209       opserr << "WARNING DistributedBandGenLinSOE::DistributedBandGenLinSOE :";
00210       opserr << " ran out of memory for A (size,super,sub) (";
00211       opserr << size <<", " << numSuperD << ", " << numSubD << ") \n";
00212       Asize = 0; size = 0; numSubD = 0; numSuperD = 0;
00213       result= -1;
00214     }
00215     else  
00216       Asize = newSize;
00217   }
00218   
00219   // zero the matrix
00220   for (int i=0; i<Asize; i++)
00221     A[i] = 0;
00222   
00223   factored = false;
00224 
00225 
00226   
00227   if (size > Bsize) { // we have to get space for the vectors
00228     
00229     // delete the old   
00230     if (B != 0) delete [] B;
00231     if (X != 0) delete [] X;
00232     if (myB != 0) delete [] myB;
00233     
00234     // create the new
00235     B = new double[size];
00236     X = new double[size];
00237     myB = new double[size];
00238     
00239     if (B == 0 || X == 0 || myB == 0) {
00240       opserr << "WARNING DistributedBandGenLinSOE::DistributedBandGenLinSOE :";
00241       opserr << " ran out of memory for vectors (size) (";
00242       opserr << size << ") \n";
00243       Bsize = 0; size = 0; numSubD = 0; numSuperD = 0;
00244       result = -1;
00245     }
00246     else 
00247       Bsize = size;
00248   }
00249   
00250   // zero the vectors
00251   for (int j=0; j<size; j++) {
00252     B[j] = 0;
00253     X[j] = 0;
00254     myB[j] = 0;
00255   }
00256   
00257   // get new Vector objects if size has changes
00258   if (oldSize != size) {
00259     if (vectX != 0) 
00260       delete vectX;
00261     
00262     if (vectB != 0) 
00263       delete vectB;
00264     
00265     if (myVectB != 0)
00266       delete myVectB;
00267 
00268     vectX = new Vector(X,size);
00269     vectB = new Vector(B,size);
00270     myVectB = new Vector(myB, size);
00271   }
00272 
00273     // invoke setSize() on the Solver
00274   LinearSOESolver *theSolvr = this->getSolver();
00275   int solverOK = theSolvr->setSize();
00276   if (solverOK < 0) {
00277     opserr << "WARNING:DistributedBandGenLinSOE::setSize :";
00278     opserr << " solver failed setSize()\n";
00279     return solverOK;
00280   }    
00281   
00282   return result;    
00283 }
00284 
00285 
00286 int 
00287 DistributedBandGenLinSOE::addA(const Matrix &m, const ID &id, double fact)
00288 {
00289   // check for a quick return 
00290   if (fact == 0.0)  return 0;
00291   
00292   // check that m and id are of similar size
00293   int idSize = id.Size();    
00294   if (idSize != m.noRows() && idSize != m.noCols()) {
00295     opserr << "BandGenLinSOE::addA()    - Matrix and ID not of similar sizes\n";
00296     return -1;
00297   }
00298   
00299   int ldA = 2*numSubD + numSuperD + 1;
00300   ID *theMap = 0;
00301   if (numChannels > 0)
00302     theMap = localCol[0];
00303 
00304   if (fact == 1.0) { // do not need to multiply 
00305     for (int i=0; i<idSize; i++) {
00306       int col = id(i);
00307       if (col < size && col >= 0) {
00308         // double *coliiPtr = A + col*ldA + numSubD + numSuperD;
00309         
00310         double *coliiPtr;
00311         if (processID == 0)
00312           coliiPtr = A + col*ldA + numSubD + numSuperD;
00313         else
00314           coliiPtr = A + ((*theMap)(col))*ldA + numSubD + numSuperD;
00315         
00316         for (int j=0; j<idSize; j++) {
00317           int row = id(j);
00318           if (row <size && row >= 0) {              
00319             int diff = col - row;
00320             if (diff > 0) {
00321               if (diff <= numSuperD) {
00322                 double *APtr = coliiPtr - diff;
00323                 *APtr += m(j,i);
00324               }                 
00325               
00326             } else {
00327               diff *= -1;
00328               if (diff <= numSubD) {
00329                 double *APtr = coliiPtr + diff;
00330                 *APtr += m(j,i);
00331               }
00332             }
00333           }
00334         }  // for j
00335       } 
00336     }  // for i
00337   } else {
00338     for (int i=0; i<idSize; i++) {
00339       int col = id(i);
00340       if (col < size && col >= 0) {
00341         // double *coliiPtr = A + col*ldA + numSubD + numSuperD;
00342         
00343         double *coliiPtr;
00344         if (processID == 0)
00345           coliiPtr = A + col*ldA + numSubD + numSuperD;
00346         else
00347           coliiPtr = A + (*theMap)(col)*ldA + numSubD + numSuperD;
00348 
00349         for (int j=0; j<idSize; j++) {
00350           int row = id(j);
00351           if (row <size && row >= 0) {              
00352             int diff = col - row;
00353             if (diff > 0) {
00354               if (diff <= numSuperD) {
00355                 double *APtr = coliiPtr - diff;
00356                 *APtr += m(j,i) *fact;
00357               }
00358             } else {
00359               diff *= -1;
00360               if (diff <= numSubD) {
00361                 double *APtr = coliiPtr + diff;
00362                 *APtr += m(j,i) *fact;
00363               }
00364             }
00365           }
00366         }  // for j
00367       } 
00368     }  // for i
00369   }    
00370 
00371   return 0;
00372 }
00373 
00374 int 
00375 DistributedBandGenLinSOE::solve(void)
00376 {
00377   static ID result(1);
00378 
00379   //
00380   // if subprocess send B and A and receive back result X, B & result
00381   //
00382 
00383   if (processID != 0) {
00384     Channel *theChannel = theChannels[0];
00385 
00386     // send B
00387     theChannel->sendVector(0, 0, *myVectB);
00388 
00389     // send A in packets placed in vector X
00390     //    Vector vectA(A, Asize);    
00391     if (factored == false) {
00392       Vector vectA(A, sizeWork);        
00393       theChannel->sendVector(0, 0, vectA);
00394     }
00395 
00396     // receive X,B and result
00397     theChannel->recvVector(0, 0, *vectX);
00398     theChannel->recvVector(0, 0, *vectB);
00399     theChannel->recvID(0, 0, result);
00400     
00401     factored = true;
00402   } 
00403 
00404   //
00405   // if main process, recv B & A from all, solve and send back X, B & result
00406   //
00407 
00408   else {
00409 
00410     // add P0 contribution to B
00411     *vectB = *myVectB;
00412 
00413     // receive X and A contribution from subprocess & add them in
00414     for (int j=0; j<numChannels; j++) {
00415 
00416       // get X & add
00417       Channel *theChannel = theChannels[j];
00418       theChannel->recvVector(0, 0, *vectX);
00419       *vectB += *vectX;
00420 
00421       // get A & add using local map
00422       if (factored == false) {
00423         const ID &localMap = *(localCol[j]);
00424         int ldA = 2*numSubD + numSuperD + 1;    
00425         int localSize = localMap.Size() * ldA;
00426         Vector vectA(workArea, localSize);    
00427         theChannel->recvVector(0, 0, vectA);
00428 
00429         int loc = 0;
00430         for (int i=0; i<localMap.Size(); i++) {
00431           int pos = localMap(i)*ldA;
00432           for (int k=0; k<ldA; k++) 
00433             A[pos++] += workArea[loc++];
00434         }    
00435       }
00436     }
00437     
00438     // solve
00439     result(0) = this->LinearSOE::solve();
00440 
00441     // send results back
00442     for (int j=0; j<numChannels; j++) {
00443       Channel *theChannel = theChannels[j];
00444       theChannel->sendVector(0, 0, *vectX);
00445       theChannel->sendVector(0, 0, *vectB);
00446       theChannel->sendID(0, 0, result);      
00447     }
00448   } 
00449 
00450   return result(0);
00451 }       
00452 
00453 
00454 int 
00455 DistributedBandGenLinSOE::addB(const Vector &v, const ID &id, double fact)
00456 {
00457     
00458     // check for a quick return 
00459     if (fact == 0.0)  return 0;
00460 
00461     // check that m and id are of similar size
00462     int idSize = id.Size();        
00463     if (idSize != v.Size() ) {
00464         opserr << "BandSPDLinSOE::addB() - Vector and ID not of similar sizes\n";
00465         return -1;
00466     }    
00467     
00468     if (fact == 1.0) { // do not need to multiply if fact == 1.0
00469         for (int i=0; i<idSize; i++) {
00470             int pos = id(i);
00471             if (pos <size && pos >= 0)
00472                 myB[pos] += v(i);
00473         }
00474     } else if (fact == -1.0) {
00475         for (int i=0; i<idSize; i++) {
00476             int pos = id(i);
00477             if (pos <size && pos >= 0)
00478                 myB[pos] -= v(i);
00479         }
00480     } else {
00481         for (int i=0; i<idSize; i++) {
00482             int pos = id(i);
00483             if (pos <size && pos >= 0)
00484                 myB[pos] += v(i) * fact;
00485         }
00486     }   
00487     return 0;
00488 }
00489 
00490 
00491 int
00492 DistributedBandGenLinSOE::setB(const Vector &v, double fact)
00493 {
00494     // check for a quick return 
00495     if (fact == 0.0)  return 0;
00496 
00497 
00498     if (v.Size() != size) {
00499         opserr << "WARNING DistributedBandGenLinSOE::setB() -";
00500         opserr << " incomptable sizes " << size << " and " << v.Size() << endln;
00501         return -1;
00502     }
00503     
00504     if (fact == 1.0) { // do not need to multiply if fact == 1.0
00505         for (int i=0; i<size; i++) {
00506             myB[i] = v(i);
00507         }
00508     } else if (fact == -1.0) {
00509         for (int i=0; i<size; i++) {
00510             myB[i] = -v(i);
00511         }
00512     } else {
00513         for (int i=0; i<size; i++) {
00514             myB[i] = v(i) * fact;
00515         }
00516     }   
00517     return 0;
00518 }
00519 
00520 void 
00521 DistributedBandGenLinSOE::zeroB(void)
00522 {
00523   double *Bptr = myB;
00524   for (int i=0; i<size; i++)
00525     *Bptr++ = 0;
00526 }
00527 
00528 
00529 const Vector &
00530 DistributedBandGenLinSOE::getB(void)
00531 {
00532   if (processID != 0) {
00533     Channel *theChannel = theChannels[0];
00534 
00535     // send B & recv merged B
00536     theChannel->sendVector(0, 0, *myVectB);
00537     theChannel->recvVector(0, 0, *vectB);
00538   } 
00539 
00540   //
00541   // if main process, recv B & A from all, solve and send back X, B & result
00542   //
00543 
00544   else {
00545 
00546     *vectB = *myVectB;
00547 
00548     Vector remoteB(workArea, size);    
00549     // receive X and A contribution from subprocess & add them in
00550 
00551     for (int j=0; j<numChannels; j++) {
00552 
00553       Channel *theChannel = theChannels[j];
00554       theChannel->recvVector(0, 0, remoteB);
00555       *vectB += remoteB;
00556     }
00557   
00558     // send results back
00559     for (int j=0; j<numChannels; j++) {
00560       Channel *theChannel = theChannels[j];
00561       theChannel->sendVector(0, 0, *vectB);
00562     }
00563   } 
00564 
00565   return *vectB;
00566 }       
00567 
00568   
00569 int 
00570 DistributedBandGenLinSOE::sendSelf(int commitTag, Channel &theChannel)
00571 {
00572   int sendID =0;
00573 
00574   // if P0 check if already sent. If already sent use old processID; if not allocate a new process 
00575   // id for remote part of object, enlarge channel * to hold a channel * for this remote object.
00576 
00577   // if not P0, send current processID
00578 
00579   if (processID == 0) {
00580 
00581     // check if already using this object
00582     bool found = false;
00583     for (int i=0; i<numChannels; i++)
00584       if (theChannels[i] == &theChannel) {
00585         sendID = i+1;
00586         found = true;
00587       }
00588 
00589     // if new object, enlarge Channel pointers to hold new channel * & allocate new ID
00590     if (found == false) {
00591       int nextNumChannels = numChannels + 1;
00592       Channel **nextChannels = new Channel *[nextNumChannels];
00593       if (nextNumChannels == 0) {
00594         opserr << "DistributedBandGenLinSOE::sendSelf() - failed to allocate channel array of size: " << 
00595           nextNumChannels << endln;
00596         return -1;
00597       }
00598       for (int i=0; i<numChannels; i++)
00599         nextChannels[i] = theChannels[i];
00600       nextChannels[numChannels] = &theChannel;
00601       
00602       numChannels = nextNumChannels;
00603       
00604       if (theChannels != 0)
00605         delete [] theChannels;
00606       
00607       theChannels = nextChannels;
00608       
00609       if (localCol != 0)
00610         delete [] localCol;
00611       localCol = new ID *[numChannels];
00612       if (localCol == 0) {
00613         opserr << "DistributedBandGenLinSOE::sendSelf() - failed to allocate id array of size: " << 
00614           nextNumChannels << endln;
00615         return -1;
00616       }
00617       for (int i=0; i<numChannels; i++)
00618         localCol[i] = 0;    
00619 
00620       // allocate new processID for remote object
00621       sendID = numChannels;
00622     }
00623 
00624   } else 
00625     sendID = processID;
00626 
00627 
00628   // send remotes processID
00629   ID idData(1);
00630   idData(0) = sendID;
00631   
00632   int res = theChannel.sendID(0, commitTag, idData);
00633   if (res < 0) {
00634     opserr <<"WARNING DistributedBandGenLinSOE::sendSelf() - failed to send data\n";
00635     return -1;
00636   }
00637 
00638   return 0;
00639 }
00640 
00641 
00642 int 
00643 DistributedBandGenLinSOE::recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker)
00644 {
00645   ID idData(1);
00646   int res = theChannel.recvID(0, commitTag, idData);
00647   if (res < 0) {
00648     opserr <<"WARNING DistributedBandGenLinSOE::recvSelf() - failed to send data\n";
00649     return -1;
00650   }           
00651   processID = idData(0);
00652 
00653   numChannels = 1;
00654   theChannels = new Channel *[1];
00655   theChannels[0] = &theChannel;
00656 
00657 
00658   localCol = new ID *[numChannels];
00659   for (int i=0; i<numChannels; i++)
00660     localCol[i] = 0;
00661 
00662   return 0;
00663 }
00664 
00665 
00666 int
00667 DistributedBandGenLinSOE::setProcessID(int dTag) 
00668 {
00669   processID = dTag;
00670   return 0;
00671 }
00672 
00673 int
00674 DistributedBandGenLinSOE::setChannels(int nChannels, Channel **theC)
00675 {
00676   numChannels = nChannels;
00677 
00678   if (theChannels != 0)
00679     delete [] theChannels;
00680 
00681   theChannels = new Channel *[numChannels];
00682   for (int i=0; i<numChannels; i++)
00683     theChannels[i] = theC[i];
00684 
00685 
00686   localCol = new ID *[nChannels];
00687   for (int i=0; i<numChannels; i++)
00688     localCol[i] = 0;
00689 
00690   return 0;
00691 }

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