PetscSOE.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.6 $
00022 // $Date: 2006/06/15 00:20:06 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/system_of_eqn/linearSOE/petsc/PetscSOE.cpp,v $
00024                                                                         
00025 // Written: fmk & om
00026 // Created: 7/98
00027 // Revision: A
00028 //
00029 // Description: This file contains the implementation for PetscSOE
00030 
00031 
00032 #include "PetscSOE.h"
00033 #include "PetscSolver.h"
00034 #include <petscvec.h>
00035 #include <Matrix.h>
00036 #include <Graph.h>
00037 #include <Vertex.h>
00038 #include <VertexIter.h>
00039 #include <f2c.h>
00040 #include <math.h>
00041 #include <Channel.h>
00042 #include <FEM_ObjectBroker.h>
00043 
00044 PetscSOE::PetscSOE(PetscSolver &theSOESolver, int bs)
00045 :LinearSOE(theSOESolver, LinSOE_TAGS_PetscSOE),
00046  isFactored(0),size(0), processID(0), numProcesses(0), B(0), X(0), 
00047  indices(0), vectX(0), vectB(0), A(0), x(0), b(0), blockSize(bs),
00048  numChannels(0), theChannels(0), localCol(0)
00049 {
00050   theSOESolver.setLinearSOE(*this);
00051 }
00052 
00053 
00054 int
00055 PetscSOE::getNumEqn(void) const
00056 {
00057   return size;
00058 }
00059     
00060 PetscSOE::~PetscSOE()
00061 {
00062   if (theChannels != 0)
00063     delete [] theChannels;
00064 
00065   if (localCol != 0)
00066     for (int i=0; i<numChannels; i++)
00067       if (localCol[i] != 0)
00068         delete localCol[i];
00069   delete [] localCol;
00070   
00071   if (vectX != 0) delete vectX;  
00072   if (vectB != 0) delete vectB;  
00073 
00074   if (B != 0) delete [] B;
00075   if (X != 0) delete [] X;
00076   
00077   // invoke the petsc destructors
00078   if (A != 0) MatDestroy(A);
00079   if (b != 0) VecDestroy(b);
00080   if (x != 0) VecDestroy(x);
00081 }
00082 
00083 
00084 int 
00085 PetscSOE::setSize(Graph &theGraph)
00086 {
00087   PetscInitialize(0, PETSC_NULL, (char *)0, PETSC_NULL);
00088   MPI_Comm_size(PETSC_COMM_WORLD, &numProcesses);
00089   MPI_Comm_rank(PETSC_COMM_WORLD, &processID);
00090   
00091   int result = 0;
00092   int ierr = 0;
00093 
00094     // 
00095     // first determine system size
00096     //
00097 
00098     if (numProcesses == 1) {
00099       
00100       // if single process, the system size is size of graph
00101       size = theGraph.getNumVertex();
00102       isFactored = 0;
00103 
00104     } else {
00105 
00106       // first determine local max
00107       size = 0;
00108       isFactored = 0;
00109       VertexIter &theVertices = theGraph.getVertices();
00110       Vertex *theVertex;
00111       while ((theVertex = theVertices()) != 0) {
00112         int vertexTag = theVertex->getTag();
00113         if (vertexTag > size) 
00114           size = vertexTag;
00115       }
00116 
00117       static ID data(1);
00118 
00119       // all local max's sent to P0 which determines the max
00120       // and informs all others
00121 
00122       if (processID != 0) {
00123         Channel *theChannel = theChannels[0];
00124         
00125         data(0) = size;
00126         theChannel->sendID(0, 0, data);
00127         theChannel->recvID(0, 0, data);
00128         
00129         size = data(0);
00130       } else {
00131 
00132         for (int j=0; j<numChannels; j++) {
00133           Channel *theChannel = theChannels[j];
00134           theChannel->recvID(0, 0, data);
00135           if (data(0) > size)
00136             size = data(0);
00137         }
00138         data(0) = size;
00139         for (int j=0; j<numChannels; j++) {
00140           Channel *theChannel = theChannels[j];
00141           theChannel->sendID(0, 0, data);
00142         }
00143       }
00144       size = size+1; // vertices numbered 0 through n-1
00145     }
00146 
00147     // invoke the petsc destructors
00148     if (A != 0) MatDestroy(A);
00149     if (b != 0) VecDestroy(b);
00150     if (x != 0) VecDestroy(x);
00151     
00152     //
00153     // now we create the opensees vector objects
00154     //
00155 
00156     // delete the old vectors
00157     if (B != 0) delete [] B;
00158     if (X != 0) delete [] X;
00159     
00160     // create the new
00161     B = new double[size];
00162     X = new double[size];
00163     
00164     if (B == 0 || X == 0) {
00165       opserr << "WARNING PetscSOE::PetscSOE :";
00166       opserr << " ran out of memory for vectors (size) (";
00167       opserr << size << ") \n";
00168       size = 0; 
00169       result = -1;
00170     }
00171     
00172     // zero the vectors
00173     for (int j=0; j<size; j++) {
00174       B[j] = 0;
00175       X[j] = 0;
00176     }
00177     
00178     if (vectX != 0) 
00179       delete vectX;
00180     
00181     if (vectB != 0) 
00182       delete vectB;
00183     
00184     vectX = new Vector(X, size);
00185     vectB = new Vector(B, size);
00186 
00187     // 
00188     // now create petsc matrix and vector objects
00189     //
00190 
00191     if (numProcesses == 1) {
00192     
00193       // we determine the number of non-zeros & number of nonzero's
00194       // in each row of A
00195       int *rowA = new int[size];  // will contain no of non-zero entries
00196       // in each row
00197       
00198       int NNZ = 0;
00199       for (int a=0; a<size; a++) {
00200         Vertex *theVertex = theGraph.getVertexPtr(a);
00201         if (theVertex == 0) {
00202           opserr << "WARNING:PetscSOE::setSize :";
00203           opserr << " vertex " << a << " not in graph! - size set to 0\n";
00204           size = 0;
00205           return -1;
00206         }
00207         
00208         const ID &theAdjacency = theVertex->getAdjacency();
00209         int idSize = theAdjacency.Size();
00210         
00211         NNZ += idSize +1;
00212         rowA[a] = idSize +1;  // +1 for the diagonal entry
00213       }
00214 
00215       // 
00216       // Call Petsc VecCreate & MatCreate; NOTE: using previously allocated storage for vectors
00217       //      
00218 
00219       //      ierr = PetscOptionsGetInt(PETSC_NULL, "-n", &size, &flg); CHKERRQ(ierr);
00220       
00221       if (blockSize == 1) {
00222         ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, size, size, 0, rowA, &A); CHKERRQ(ierr);
00223       } else {
00224         ierr = MatCreateSeqBAIJ(PETSC_COMM_SELF, blockSize, size,size, 0, rowA, &A); CHKERRQ(ierr);
00225       }
00226       
00227       ierr = VecCreateSeqWithArray(PETSC_COMM_WORLD, size, X, &x); CHKERRQ(ierr); 
00228       ierr = VecCreateSeqWithArray(PETSC_COMM_WORLD, size, B, &b); CHKERRQ(ierr); 
00229 
00230       // invoke setSize() on the Solver
00231       LinearSOESolver *tSolver = this->getSolver();
00232       int solverOK = tSolver->setSize();
00233       if (solverOK < 0) {
00234         opserr << "WARNING:PetscSOE::setSize :";
00235         opserr << " solver failed setSize()\n";
00236         return solverOK;
00237       }    
00238       
00239       // clear up the memory we used
00240       delete [] rowA;
00241 
00242 
00243     } else {
00244 
00245       // 
00246       // Call Petsc VecCreate & MatCreate; NOTE: using previously allocated storage for vectors
00247       // 
00248       //
00249 
00250       ierr = PetscOptionsGetInt(PETSC_NULL, "-n", &size, &flg); CHKERRQ(ierr);
00251       ierr = MatCreate(PETSC_COMM_WORLD, PETSC_DECIDE, PETSC_DECIDE,size, size, &A); CHKERRQ(ierr);
00252       ierr = MatSetFromOptions(A);CHKERRQ(ierr);
00253       ierr = MatGetOwnershipRange(A, &startRow, &endRow);CHKERRQ(ierr);
00254 
00255       ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD, endRow-startRow, size, &X[startRow],  &x); CHKERRQ(ierr);
00256       ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD, endRow-startRow, size, &B[startRow],  &b); CHKERRQ(ierr);
00257 
00258       // invoke setSize() on the Solver
00259       LinearSOESolver *tSolver = this->getSolver();
00260       int solverOK = tSolver->setSize();
00261       if (solverOK < 0) {
00262         opserr << "WARNING:PetscSOE::setSize :";
00263         opserr << " solver failed setSize()\n";
00264         return solverOK;
00265       }    
00266     }
00267 
00268     return result;    
00269 }
00270 
00271 
00272 int 
00273 PetscSOE::addA(const Matrix &m, const ID &id, double fact)
00274 {
00275   isFactored = 0;
00276 
00277     // check for a quick return 
00278     if (fact == 0.0)  return 0;
00279 
00280     
00281     // check that m and id are of similar size
00282     int idSize = id.Size();    
00283     if (idSize != m.noRows() && idSize != m.noCols()) {
00284         opserr << "PetscSOE::addA() - Matrix and ID not of similar sizes\n";
00285         return -1;
00286     }
00287     
00288     int n = id.Size();
00289     int row;
00290     int col;
00291     double value;
00292     for (int i=0; i<n; i++) {
00293       row = id(i);
00294       if (row >= 0) {
00295         for (int j=0; j<n; j++) {
00296           col = id(j);
00297           if (col >= 0) {
00298             value = m(i,j)*fact;
00299             int ierr = MatSetValues(A,1,&row,1,&col,&value,ADD_VALUES); 
00300             if (ierr) opserr << processID << " " << row << " " << col << endln; 
00301             CHKERRQ(ierr); 
00302           }
00303         }
00304       }
00305     }
00306 
00307     return 0;
00308 }
00309 
00310     
00311 int 
00312 PetscSOE::addB(const Vector &v, const ID &id, double fact)
00313 {
00314     // check for a quick return 
00315     if (fact == 0.0)  return 0;
00316 
00317 
00318     // check that m and id are of similar size
00319     int idSize = id.Size();        
00320     if (idSize != v.Size() ) {
00321         opserr << "BandGenLinSOE::addB()        - Vector and ID not of similar sizes\n";
00322         return -1;
00323     }    
00324     
00325     if (fact == 1.0) { // do not need to multiply if fact == 1.0
00326         for (int i=0; i<idSize; i++) {
00327             int pos = id(i);
00328             if (pos <size && pos >= 0)
00329                 B[pos] += v(i);
00330         }
00331     } else if (fact == -1.0) {
00332         for (int i=0; i<idSize; i++) {
00333             int pos = id(i);
00334             if (pos <size && pos >= 0)
00335                 B[pos] -= v(i);
00336         }
00337     } else {
00338         for (int i=0; i<idSize; i++) {
00339             int pos = id(i);
00340             if (pos <size && pos >= 0)
00341                 B[pos] += v(i) * fact;
00342         }
00343     }   
00344     return 0;
00345 }
00346 
00347 
00348 int
00349 PetscSOE::setB(const Vector &v, double fact)
00350 {
00351     // check for a quick return 
00352     if (fact == 0.0)  return 0;
00353 
00354 
00355     if (v.Size() != size) {
00356         opserr << "WARNING BandGenLinSOE::setB() -";
00357         opserr << " incomptable sizes " << size << " and " << v.Size() << endln;
00358         return -1;
00359     }
00360     
00361     if (fact == 1.0) { // do not need to multiply if fact == 1.0
00362         for (int i=0; i<size; i++) {
00363             B[i] = v(i);
00364         }
00365     } else if (fact == -1.0) {
00366         for (int i=0; i<size; i++) {
00367             B[i] = -v(i);
00368         }
00369     } else {
00370         for (int i=0; i<size; i++) {
00371             B[i] = v(i) * fact;
00372         }
00373     }   
00374     return 0;
00375 }
00376 
00377 
00378 void 
00379 PetscSOE::zeroA(void)
00380 {
00381   isFactored = 0;
00382   MatZeroEntries(A);
00383 }
00384         
00385 void 
00386 PetscSOE::zeroB(void)
00387 {
00388   double *Bptr = B;
00389   for (int i=0; i<size; i++)
00390     *Bptr++ = 0;
00391 }
00392 
00393 
00394 const Vector &
00395 PetscSOE::getX(void)
00396 {
00397   if (vectX == 0) {
00398     opserr << "FATAL PetscSOE::getX - vectX == 0!";
00399     exit(-1);
00400   }  
00401   return *vectX;
00402 }
00403 
00404 
00405 const Vector &
00406 PetscSOE::getB(void)
00407 {
00408   static Vector recvVector(1);
00409   static Vector myVectorB(1);
00410 
00411   if (vectB == 0) {
00412     opserr << "FATAL PetscSOE::getB - vectB == 0!";
00413     exit(-1);
00414   }    
00415 
00416   if (numProcesses > 1) {
00417       if (myVectorB.Size() != size) 
00418         myVectorB.resize(size);
00419 
00420     if (processID != 0) {
00421       Channel *theChannel = theChannels[0];
00422       
00423       theChannel->sendVector(0, 0, *vectB);
00424       theChannel->recvVector(0, 0, myVectorB);
00425     } else {
00426       if (recvVector.Size() != size) 
00427         recvVector.resize(size);
00428 
00429       myVectorB = *vectB;
00430       for (int j=0; j<numChannels; j++) {
00431         Channel *theChannel = theChannels[j];
00432         theChannel->recvVector(0, 0, recvVector);
00433         myVectorB += recvVector;
00434       }
00435       for (int j=0; j<numChannels; j++) {
00436         Channel *theChannel = theChannels[j];
00437         theChannel->sendVector(0, 0, myVectorB);
00438       }
00439     }
00440     return myVectorB;
00441 
00442   } else
00443     return *vectB;
00444 }
00445 
00446 
00447 double 
00448 PetscSOE::normRHS(void)
00449 {
00450   this->getB();
00451   double norm =0.0;
00452   double *Bptr = B;
00453   for (int i=0; i<size; i++) {
00454     double Yi = *Bptr++;
00455     norm += Yi*Yi;
00456   }
00457   return sqrt(norm);
00458 }    
00459 
00460 
00461 void 
00462 PetscSOE::setX(int loc, double value)
00463 {
00464   if (loc < size && loc >= 0)
00465         X[loc] = value;
00466 }
00467 
00468 void 
00469 PetscSOE::setX(const Vector &xData)
00470 {
00471   if (xData.Size() == size && vectX != 0)
00472     *vectX = xData;
00473 }
00474 
00475 int
00476 PetscSOE::setSolver(PetscSolver &newSolver)
00477 {
00478     newSolver.setLinearSOE(*this);
00479     
00480     if (size != 0) {
00481         int solverOK = newSolver.setSize();
00482         if (solverOK < 0) {
00483             opserr << "WARNING:PetscSOE::setSolver :";
00484             opserr << "the new solver could not setSeize() - staying with old\n";
00485             return solverOK;
00486         }
00487     }   
00488     
00489     return this->LinearSOE::setSolver(newSolver);
00490 }
00491 
00492 
00493 int 
00494 PetscSOE::sendSelf(int cTag, Channel &theChannel)
00495 {
00496   processID = 0;
00497   int sendID =0;
00498 
00499   // if P0 check if already sent. If already sent use old processID; if not allocate a new process 
00500   // id for remote part of object, enlarge channel * to hold a channel * for this remote object.
00501 
00502   // if not P0, send current processID
00503 
00504   if (processID == 0) {
00505 
00506     // check if already using this object
00507     bool found = false;
00508     for (int i=0; i<numChannels; i++)
00509       if (theChannels[i] == &theChannel) {
00510         sendID = i+1;
00511         found = true;
00512       }
00513 
00514     // if new object, enlarge Channel pointers to hold new channel * & allocate new ID
00515     if (found == false) {
00516       int nextNumChannels = numChannels + 1;
00517       Channel **nextChannels = new Channel *[nextNumChannels];
00518       if (nextNumChannels == 0) {
00519         opserr << "DistributedBandGenLinSOE::sendSelf() - failed to allocate channel array of size: " << 
00520           nextNumChannels << endln;
00521         return -1;
00522       }
00523       for (int i=0; i<numChannels; i++)
00524         nextChannels[i] = theChannels[i];
00525       nextChannels[numChannels] = &theChannel;
00526       numChannels = nextNumChannels;
00527       
00528       if (theChannels != 0)
00529         delete [] theChannels;
00530       
00531       theChannels = nextChannels;
00532       
00533   if (localCol != 0)
00534         delete [] localCol;
00535       localCol = new ID *[numChannels];
00536       if (localCol == 0) {
00537         opserr << "DistributedBandGenLinSOE::sendSelf() - failed to allocate id array of size: " << 
00538           nextNumChannels << endln;
00539         return -1;
00540       }
00541       for (int i=0; i<numChannels; i++)
00542         localCol[i] = 0;    
00543 
00544       // allocate new processID for remote object
00545       sendID = numChannels;
00546     }
00547 
00548   } else 
00549     sendID = processID;
00550 
00551   return 0;
00552 }
00553 
00554 
00555 int 
00556 PetscSOE::recvSelf(int cTag, Channel &theChannel, 
00557                    FEM_ObjectBroker &theBroker)
00558 {
00559   numChannels = 1;
00560   theChannels = new Channel *[1];
00561   theChannels[0] = &theChannel;
00562 
00563   localCol = new ID *[numChannels];
00564   for (int i=0; i<numChannels; i++)
00565     localCol[i] = 0;
00566 
00567   return 0;
00568 }
00569 
00570 int
00571 PetscSOE::setChannels(int nChannels, Channel **theC)
00572 {
00573   numChannels = nChannels;
00574 
00575   if (theChannels != 0)
00576     delete [] theChannels;
00577 
00578   theChannels = new Channel *[numChannels];
00579   for (int i=0; i<numChannels; i++)
00580     theChannels[i] = theC[i];
00581 
00582 
00583   localCol = new ID *[nChannels];
00584   for (int i=0; i<numChannels; i++)
00585     localCol[i] = 0;
00586 
00587   return 0;
00588 }

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