SymSparseLinSOE.cpp

Go to the documentation of this file.
00001 // File: ~/system_of_eqn/linearSOE/symLinSolver/SymSparseLinSOE.CPP
00002 //
00003 // Written: Jun Peng  (junpeng@stanford.edu)
00004 //          Advisor: Prof. Kincho H. Law
00005 //          Stanford University
00006 // Created: 12/1998
00007 // Revised: 12/2001
00008 //
00009 // Description: This file contains the class definition for 
00010 // SymSparseinSolver. It solves the SymSparseLinSOEobject by calling
00011 // some "C" functions. The solver used here is a symmtric generalized sparse
00012 // solver. The user can choose three different ordering scheme.
00013 //
00014 // What: "@(#) SymSparseLinSOE.C, revA"
00015 
00016 
00017 #include <fstream>
00018 #include <stdlib.h>
00019 
00020 #include <SymSparseLinSOE.h>
00021 #include <SymSparseLinSolver.h>
00022 #include <Matrix.h>
00023 #include <Graph.h>
00024 #include <Vertex.h>
00025 #include <VertexIter.h>
00026 #include <math.h>
00027 #include <Channel.h>
00028 #include <FEM_ObjectBroker.h>
00029 
00030 
00031 SymSparseLinSOE::SymSparseLinSOE(SymSparseLinSolver &the_Solver, int lSparse)
00032 :LinearSOE(the_Solver, LinSOE_TAGS_SymSparseLinSOE),
00033  size(0), nnz(0), B(0), X(0), colA(0), rowStartA(0),
00034  vectX(0), vectB(0), 
00035  Bsize(0), factored(false),
00036  nblks(0), xblk(0), invp(0), diag(0), penv(0), rowblks(0),
00037  begblk(0), first(0) 
00038 {       
00039     the_Solver.setLinearSOE(*this);
00040     this->LSPARSE = lSparse;
00041 }
00042 
00043 
00044 /* A destructor for cleanning memory.
00045  * For diag and penv, it is rather straightforward to clean.
00046  * For row segments, since the memory of nz is allocated for each
00047  * row, the deallocated needs some special care.
00048  */
00049 SymSparseLinSOE::~SymSparseLinSOE()
00050 {
00051     // free the diagonal vector
00052     if (diag != NULL) free(diag);
00053 
00054     // free the diagonal blocks
00055     if (penv != NULL) {
00056         if (penv[0] != NULL) {
00057             free(penv[0]);
00058         }
00059         free(penv);
00060     } 
00061 
00062     // free the row segments.
00063     OFFDBLK *blkPtr = first;
00064     OFFDBLK *tempBlk;
00065     int curRow = -1;
00066 
00067     while (1) {
00068       if (blkPtr->next == blkPtr) {
00069         if (blkPtr != NULL) {
00070           free(blkPtr);
00071         }     
00072         break;
00073       }
00074 
00075       tempBlk = blkPtr->next;
00076       if (blkPtr->row != curRow) {
00077         if (blkPtr->nz != NULL) {
00078           free(blkPtr->nz);
00079         }
00080         curRow = blkPtr->row;
00081       }
00082       
00083       free(blkPtr);
00084 
00085       blkPtr = tempBlk;
00086     }
00087 
00088     // free the "C" style vectors.
00089     if (xblk != 0)  free(xblk);
00090     if (rowblks != 0)   free(rowblks);
00091     if (invp != 0)  free(invp);
00092     
00093     // free the "C++" style vectors.
00094     if (B != 0) delete [] B;
00095     if (X != 0) delete [] X;
00096     if (vectX != 0) delete vectX;    
00097     if (vectB != 0) delete vectB;
00098     if (rowStartA != 0) delete [] rowStartA;
00099     if (colA != 0) delete [] colA;
00100 }
00101 
00102 
00103 int SymSparseLinSOE::getNumEqn(void) const
00104 {
00105     return size;
00106 }
00107 
00108 
00109 /* the symbolic factorization method defined in <symbolic.c>
00110  */
00111 extern "C" int symFactorization(int *fxadj, int *adjncy, int neq, int LSPARSE, 
00112                                 int **xblkMY, int **invpMY, int **rowblksMY, 
00113                                 OFFDBLK ***begblkMY, OFFDBLK **firstMY, 
00114                                 double ***penvMY, double **diagMY);
00115 
00116 
00117 /* Based on the graph (the entries in A), set up the pair (rowStartA, colA).
00118  * It is the same as the pair (ADJNCY, XADJ).
00119  * Then perform the symbolic factorization by calling symFactorization().
00120  */
00121 int SymSparseLinSOE::setSize(Graph &theGraph)
00122 {
00123 
00124     int result = 0;
00125     int oldSize = size;
00126     size = theGraph.getNumVertex();
00127 
00128     // first itearte through the vertices of the graph to get nnz
00129     Vertex *theVertex;
00130     int newNNZ = 0;
00131     VertexIter &theVertices = theGraph.getVertices();
00132     while ((theVertex = theVertices()) != 0) {
00133         const ID &theAdjacency = theVertex->getAdjacency();
00134         newNNZ += theAdjacency.Size(); 
00135     }
00136     nnz = newNNZ;
00137  
00138     colA = new int[newNNZ];     
00139     if (colA == 0) {
00140         opserr << "WARNING SymSparseLinSOE::SymSparseLinSOE :";
00141         opserr << " ran out of memory for colA with nnz = ";
00142         opserr << newNNZ << " \n";
00143         size = 0; nnz = 0;
00144         result =  -1;
00145     } 
00146         
00147     factored = false;
00148     
00149     if (size > Bsize) { // we have to get space for the vectors
00150         
00151         // delete the old       
00152         if (B != 0) delete [] B;
00153         if (X != 0) delete [] X;
00154         if (rowStartA != 0) delete [] rowStartA;
00155 
00156         // create the new
00157         B = new double[size];
00158         X = new double[size];
00159         rowStartA = new int[size+1]; 
00160         
00161         if (B == 0 || X == 0 || rowStartA == 0) {
00162             opserr << "WARNING SymSparseLinSOE::SymSparseLinSOE :";
00163             opserr << " ran out of memory for vectors (size) (";
00164             opserr << size << ") \n";
00165             size = 0; Bsize = 0;
00166             result =  -1;
00167         } else {
00168             Bsize = size;
00169         }
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     // create new Vectors objects
00179     if (size != oldSize) {
00180          if (vectX != 0)
00181                 delete vectX;
00182 
00183          if (vectB != 0)
00184                 delete vectB;
00185         
00186          vectX = new Vector(X,size);
00187          vectB = new Vector(B,size);    
00188     }
00189 
00190     // fill in rowStartA and colA
00191     if (size != 0) {
00192         rowStartA[0] = 0;
00193         int startLoc = 0;
00194         int lastLoc = 0;
00195 
00196         for (int a=0; a<size; a++) {
00197            theVertex = theGraph.getVertexPtr(a);
00198            if (theVertex == 0) {
00199                 opserr << "WARNING:SymSparseLinSOE::setSize :";
00200                 opserr << " vertex " << a << " not in graph! - size set to 0\n";
00201                 size = 0;
00202                 return -1;
00203            }
00204 
00205            const ID &theAdjacency = theVertex->getAdjacency();
00206            int idSize = theAdjacency.Size();
00207         
00208         // now we have to place the entries in the ID into order in colA
00209            for (int i=0; i<idSize; i++) {
00210               int row = theAdjacency(i);
00211               bool foundPlace = false;
00212          
00213               for (int j=startLoc; j<lastLoc; j++)
00214                   if (colA[j] > row) { 
00215               // move the entries already there one further on
00216               // and place col in current location
00217                       for (int k=lastLoc; k>j; k--)
00218                           colA[k] = colA[k-1];
00219                       colA[j] = row;
00220                       foundPlace = true;
00221                       j = lastLoc;
00222                   }
00223                   
00224               if (foundPlace == false) // put in at the end
00225                    colA[lastLoc] = row;
00226 
00227               lastLoc++;
00228            }
00229            rowStartA[a+1] = lastLoc;;       
00230            startLoc = lastLoc;
00231         }
00232     }
00233     
00234     // call "C" function to form elimination tree and to do the symbolic factorization.
00235     nblks = symFactorization(rowStartA, colA, size, this->LSPARSE,
00236                              &xblk, &invp, &rowblks, &begblk, &first, &penv, &diag);
00237 
00238     return result;
00239 }
00240 
00241 
00242 /* Perform the element stiffness assembly here.
00243  */
00244 int SymSparseLinSOE::addA(const Matrix &in_m, const ID &in_id, double fact)
00245 {
00246    // check for a quick return
00247    if (fact == 0.0)  
00248        return 0;
00249 
00250    int idSize = in_id.Size();
00251    if (idSize == 0)  return 0;
00252 
00253    // check that m and id are of similar size
00254    if (idSize != in_m.noRows() && idSize != in_m.noCols()) {
00255        opserr << "SymSparseLinSOE::addA() ";
00256        opserr << " - Matrix and ID not of similiar sizes\n";
00257        return -1;
00258    }
00259 
00260    // construct m and id based on non-negative id values.
00261    int newPt = 0;
00262    int *id = new int[idSize];
00263    
00264    for (int jj = 0; jj < idSize; jj++) {
00265        if (in_id(jj) >= 0 && in_id(jj) < size) {
00266            id[newPt] = in_id(jj);
00267            newPt++;
00268        }
00269    }
00270 
00271    idSize = newPt;
00272    if (idSize == 0)  return 0;
00273    double *m = new double[idSize*idSize];
00274 
00275    int newII = 0;
00276    for (int ii = 0; ii < in_id.Size(); ii++) {
00277        if (in_id(ii) >= 0 && in_id(ii) < size) {
00278 
00279            int newJJ = 0;
00280            for (int jj = 0; jj < in_id.Size(); jj++) {
00281                if (in_id(jj) >= 0 && in_id(jj) < size) {
00282                    m[newII*idSize + newJJ] = in_m(ii, jj);
00283                    newJJ++;
00284                }
00285            }
00286            newII++;
00287        }
00288    }
00289 
00290    // forming the new id based on invp.
00291 
00292    int *newID = new int[idSize];
00293    int *isort = new int[idSize];
00294    if (newID == 0 || isort ==0) {
00295        opserr << "WARNING SymSparseLinSOE::SymSparseLinSOE :";
00296        opserr << " ran out of memory for vectors (newID, isort)";
00297        return -1;
00298    }
00299 
00300    for (int kk=0; kk<idSize; kk++) {
00301        newID[kk] = id[kk];
00302        if (newID[kk] >= 0)
00303            newID[kk] = invp[newID[kk]];
00304    }
00305    
00306    long int  i_eq, j_eq;
00307    int  i, j, nee, lnee;
00308    int  k, ipos, jpos;
00309    int  it, jt;
00310    int  iblk;
00311    OFFDBLK  *ptr;
00312    OFFDBLK  *saveblk;
00313    double  *fpt, *iloc, *loc;
00314 
00315    nee = idSize;
00316    lnee = nee;
00317    
00318    /* initialize isort */
00319    for( i = 0, k = 0; i < lnee ; i++ )
00320    {
00321        if( newID[i] >= 0 ) {
00322            isort[k] = i;
00323            k++;
00324        }
00325    }
00326       
00327    lnee = k;
00328 
00329    /* perform the sorting of isort here */
00330    i = k - 1;
00331    do
00332    {
00333        k = 0 ;
00334        for (j = 0 ; j < i ; j++)
00335        {  
00336            if ( newID[isort[j]] > newID[isort[j+1]]) {  
00337                isort[j] ^= isort[j+1] ;
00338                isort[j+1] ^= isort[j] ;
00339                isort[j] ^= isort[j+1] ;
00340                k = j ;
00341            }
00342       }
00343       i = k ;
00344    }  while ( k > 0) ;
00345 
00346       i = 0 ;
00347       ipos = isort[i] ;
00348       k = rowblks[newID[ipos]] ;
00349       saveblk  = begblk[k] ;
00350 
00351       /* iterate through the element stiffness matrix, assemble each entry */
00352       for (i=0; i<lnee; i++)
00353       { 
00354          ipos = isort[i] ;
00355          i_eq = newID[ipos] ;
00356          iblk = rowblks[i_eq] ;
00357          iloc = penv[i_eq +1] - i_eq ;
00358          if (k < iblk)
00359             while (saveblk->row != i_eq) saveblk = saveblk->bnext ;
00360          
00361          ptr = saveblk ;
00362          for (j=0; j< i ; j++)
00363          {   
00364             jpos = isort[j] ;
00365             j_eq = newID[jpos] ;
00366 
00367             if (ipos > jpos) {
00368                 jt = ipos;
00369                 it = jpos;
00370             } else {
00371                 it = ipos;
00372                 jt = jpos;
00373             }
00374 
00375             if (j_eq >= xblk[iblk]) /* diagonal block (profile) */
00376             {  
00377                 loc = iloc + j_eq ;
00378                 *loc += m[it*idSize + jt] * fact;
00379             } 
00380             else /* row segment */
00381             { 
00382                 while((j_eq >= (ptr->next)->beg) && ((ptr->next)->row == i_eq))
00383                     ptr = ptr->next ;
00384                 fpt = ptr->nz ;
00385                 fpt[j_eq - ptr->beg] += m[it*idSize + jt] * fact;
00386             }
00387          }
00388          diag[i_eq] += m[ipos*idSize + ipos] * fact; /* diagonal element */
00389       }
00390           
00391     delete [] newID;
00392     delete [] isort;
00393     delete [] m;
00394     delete [] id;
00395 
00396     return 0;
00397 }
00398 
00399     
00400 /* assemble the force vector B (A*X = B).
00401  */
00402 int SymSparseLinSOE::addB(const Vector &in_v, const ID &in_id, double fact)
00403 {
00404     // check for a quick return 
00405     if (fact == 0.0)  return 0;
00406 
00407     int idSize = in_id.Size();    
00408     // check that m and id are of similar size
00409     if (idSize != in_v.Size() ) {
00410         opserr << "SymSparseLinSOE::addB() ";
00411         opserr << " - Vector and ID not of similar sizes\n";
00412         return -1;
00413     } 
00414 
00415    // construct v and id based on non-negative id values.
00416    int newPt = 0;
00417    int *id = new int[idSize];
00418    double *v = new double[idSize];
00419 
00420    for (int ii = 0; ii < idSize; ii++) {
00421        if (in_id(ii) >= 0 && in_id(ii) < size) {
00422            id[newPt] = in_id(ii);
00423            v[newPt] = in_v(ii);
00424            newPt++;
00425        }
00426    }
00427 
00428    idSize = newPt;
00429    if (idSize == 0)  {
00430        delete [] id;
00431        delete [] v;
00432        return 0;
00433    }
00434     int *newID = new int[idSize];
00435     if (newID == 0) {
00436        opserr << "WARNING SymSparseLinSOE::SymSparseLinSOE :";
00437        opserr << " ran out of memory for vectors (newID)";
00438         return -1;
00439     }
00440 
00441     for (int i=0; i<idSize; i++) {
00442        newID[i] = id[i];
00443         if (newID[i] >= 0)
00444             newID[i] = invp[newID[i]];
00445     }
00446 
00447     if (fact == 1.0) { // do not need to multiply if fact == 1.0
00448         for (int i=0; i<idSize; i++) {
00449             int pos = newID[i];
00450             if (pos <size && pos >= 0)
00451                 B[pos] += v[i];
00452         }
00453     } else if (fact == -1.0) { // do not need to multiply if fact == -1.0
00454         for (int i=0; i<idSize; i++) {
00455             int pos = newID[i];
00456             if (pos <size && pos >= 0)
00457                 B[pos] -= v[i];
00458         }
00459     } else {
00460         for (int i=0; i<idSize; i++) {
00461             int pos = newID[i];
00462             if (pos <size && pos >= 0)
00463                 B[pos] += v[i] * fact;  // assemble
00464         }
00465     }   
00466 
00467     delete [] newID;
00468     delete [] v;
00469     delete [] id;
00470 
00471     return 0;
00472 }
00473 
00474 
00475 int
00476 SymSparseLinSOE::setB(const Vector &v, double fact)
00477 {
00478     // check for a quick return 
00479     if (fact == 0.0)  return 0;
00480 
00481     if (v.Size() != size) {
00482         opserr << "WARNING SymSparseLinSOE::setB() -";
00483         opserr << " incomptable sizes " << size << " and " << v.Size() << endln;
00484         return -1;
00485     }
00486     
00487     if (fact == 1.0) { // do not need to multiply if fact == 1.0
00488         for (int i=0; i<size; i++) {
00489             B[i] = v(i);
00490         }
00491     } else if (fact == -1.0) {
00492         for (int i=0; i<size; i++) {
00493             B[i] = -v(i);
00494         }
00495     } else {
00496         for (int i=0; i<size; i++) {
00497             B[i] = v(i) * fact;
00498         }
00499     }   
00500     return 0;
00501 }
00502 
00503 
00504 /* It is used to set all the entries of A to be zero.
00505  * This method will be called if the structure of A stays the same while the
00506  * value of A needs to be changed.  e.g. if Newton-Raphson method is used
00507  * for analysis, after each iteration, the A matrix needs to be updated.
00508  */
00509 void SymSparseLinSOE::zeroA(void)
00510 {
00511     memset(diag, 0, size*sizeof(double));
00512 
00513     int profileSize = penv[size] - penv[0];
00514     memset(penv[0], 0, profileSize*sizeof(double));
00515     
00516     OFFDBLK *blkPtr = first;
00517     int rLen = 0;
00518     while (1) {
00519         if (blkPtr->beg == size)  break;
00520         rLen = xblk[rowblks[blkPtr->beg]+1] - blkPtr->beg;
00521         memset(blkPtr->nz, 0, rLen*sizeof(double));
00522 
00523         blkPtr = blkPtr->next;
00524     }
00525 
00526     factored = false;
00527 }
00528         
00529 void 
00530 SymSparseLinSOE::zeroB(void)
00531 {
00532     double *Bptr = B;
00533     for (int i=0; i<size; i++)
00534         *Bptr++ = 0;
00535 }
00536 
00537 void 
00538 SymSparseLinSOE::setX(int loc, double value)
00539 {
00540     if (loc < size && loc >=0)
00541         X[loc] = value;
00542 }
00543 
00544 void
00545 SymSparseLinSOE::setX(const Vector &x)
00546 {
00547     if (x.Size() == size && vectX != 0) 
00548         *vectX = x;
00549 }
00550 
00551 
00552 const Vector &
00553 SymSparseLinSOE::getX(void)
00554 {
00555     if (vectX == 0) {
00556         opserr << "FATAL SymSparseLinSOE::getX - vectX == 0";
00557         exit(-1);
00558     }
00559     return *vectX;
00560 }
00561 
00562 const Vector &
00563 SymSparseLinSOE::getB(void)
00564 {
00565     if (vectB == 0) {
00566         opserr << "FATAL SymSparseLinSOE::getB - vectB == 0";
00567         exit(-1);
00568     }        
00569     return *vectB;
00570 }
00571 
00572 double 
00573 SymSparseLinSOE::normRHS(void)
00574 {
00575     double norm =0.0;
00576     for (int i=0; i<size; i++) {
00577         double Yi = B[i];
00578         norm += Yi*Yi;
00579     }
00580     return sqrt(norm);
00581 }    
00582 
00583 
00584 /* Create a linkage between SOE and Solver.
00585  */
00586 int SymSparseLinSOE::setSymSparseLinSolver(SymSparseLinSolver &newSolver)
00587 {
00588     newSolver.setLinearSOE(*this);
00589     
00590     if (size != 0) {
00591         int solverOK = newSolver.setSize();
00592         if (solverOK < 0) {
00593             opserr << "WARNING:SymSparseLinSOE::setSolver :";
00594             opserr << "the new solver could not setSeize() - staying with old\n";
00595             return -1;
00596         }
00597     }
00598     
00599     return this->LinearSOE::setSolver(newSolver);
00600 }
00601 
00602 
00603 int 
00604 SymSparseLinSOE::sendSelf(int cTag, Channel &theChannel)
00605 {
00606     // not implemented.
00607     return 0;
00608 }
00609 
00610 
00611 int 
00612 SymSparseLinSOE::recvSelf(int cTag, 
00613                           Channel &theChannel, FEM_ObjectBroker &theBroker)
00614 {
00615     // not implemented.
00616     return 0;
00617 }
00618 

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