ProfileSPDLinDirectSolver.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.4 $
00022 // $Date: 2003/02/14 23:02:03 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/system_of_eqn/linearSOE/profileSPD/ProfileSPDLinDirectSolver.cpp,v $
00024                                                                         
00025                                                                         
00026 // File: ~/system_of_eqn/linearSOE/ProfileSPD/ProfileSPDLinSOESolver.C
00027 //
00028 // Written: fmk 
00029 // Created: Febuary 1997
00030 // Revision: A
00031 //
00032 // Description: This file contains the implementation for ProfileSPDLinSOESolver
00033 // Description: This file contains the class definition for 
00034 // ProfileSPDLinDirectSolver. ProfileSPDLinDirectSolver is a subclass 
00035 // of LinearSOESOlver. It solves a ProfileSPDLinSOE object using
00036 // the LDL^t factorization.
00037 
00038 // What: "@(#) ProfileSPDLinDirectSolver.C, revA"
00039 
00040 #include <ProfileSPDLinDirectSolver.h>
00041 #include <ProfileSPDLinSOE.h>
00042 #include <math.h>
00043 #include <Channel.h>
00044 #include <FEM_ObjectBroker.h>
00045 
00046 ProfileSPDLinDirectSolver::ProfileSPDLinDirectSolver(double tol)
00047 :ProfileSPDLinSolver(SOLVER_TAGS_ProfileSPDLinDirectSolver),
00048  minDiagTol(tol), size(0), RowTop(0), topRowPtr(0), invD(0)
00049 {
00050 
00051 }
00052 
00053     
00054 ProfileSPDLinDirectSolver::~ProfileSPDLinDirectSolver()
00055 {
00056     if (RowTop != 0) delete [] RowTop;
00057     if (topRowPtr != 0) free((void *)topRowPtr);
00058     if (invD != 0) delete [] invD;
00059 }
00060 
00061 int
00062 ProfileSPDLinDirectSolver::setSize(void)
00063 {
00064 
00065     if (theSOE == 0) {
00066         opserr << "ProfileSPDLinDirectSolver::setSize()";
00067         opserr << " No system has been set\n";
00068         return -1;
00069     }
00070 
00071     // check for quick return 
00072     if (theSOE->size == 0)
00073         return 0;
00074     
00075     size = theSOE->size;
00076     
00077     if (RowTop != 0) delete [] RowTop;
00078     if (topRowPtr != 0) free((void *)topRowPtr);
00079     if (invD != 0) delete [] invD;
00080 
00081     RowTop = new int[size];
00082 
00083     // we cannot use topRowPtr = new (double *)[size] with the cxx compiler
00084     topRowPtr = (double **)malloc(size *sizeof(double *));
00085 
00086     invD = new double[size]; 
00087         
00088     if (RowTop == 0 || topRowPtr == 0 || invD == 0) {
00089         opserr << "Warning :ProfileSPDLinDirectSolver::ProfileSPDLinDirectSolver :";
00090         opserr << " ran out of memory for work areas \n";
00091         return -1;
00092     }
00093 
00094 
00095     // set some pointers
00096     double *A = theSOE->A;
00097     int *iDiagLoc = theSOE->iDiagLoc;
00098 
00099     // set RowTop and topRowPtr info
00100 
00101     RowTop[0] = 0;
00102     topRowPtr[0] = A;
00103     for (int j=1; j<size; j++) {
00104         int icolsz = iDiagLoc[j] - iDiagLoc[j-1];
00105         RowTop[j] = j - icolsz +  1;
00106         topRowPtr[j] = &A[iDiagLoc[j-1]]; // FORTRAN array indexing in iDiagLoc
00107     }
00108 
00109     size = theSOE->size;
00110     return 0;
00111 }
00112 
00113 
00114 int 
00115 ProfileSPDLinDirectSolver::solve(void)
00116 {
00117 
00118     // check for quick returns
00119     if (theSOE == 0) {
00120         opserr << "ProfileSPDLinDirectSolver::solve(void): ";
00121         opserr << " - No ProfileSPDSOE has been assigned\n";
00122         return -1;
00123     }
00124     
00125     if (theSOE->size == 0)
00126         return 0;
00127 
00128     // set some pointers
00129     double *B = theSOE->B;
00130     double *X = theSOE->X;
00131     int theSize = theSOE->size;
00132     // copy B into X
00133     for (int ii=0; ii<theSize; ii++)
00134         X[ii] = B[ii];
00135 
00136     /*
00137       for (int iii=0; iii<theSize; iii++) {
00138       int rowiiitop = RowTop[iii];
00139       double *ajiptr = topRowPtr[iii];
00140       opserr << "\n COLUMN " << iii << " TopRow " << rowiiitop << " -> ";
00141       for (int jjj = rowiiitop; jjj <=iii; jjj++)
00142       opserr << *ajiptr++ << " ";
00143       }
00144       opserr << endln;
00145 
00146       for (int iii=0; iii<theSOE->size; iii++) {
00147       opserr << "COLUMN " << iii << " Biii -> " << X[iii] << endln;
00148       }
00149       opserr << endln;
00150       */
00151 
00152     
00153     if (theSOE->isAfactored == false)  {
00154 
00155         // FACTOR & SOLVE
00156         double *ajiPtr, *akjPtr, *akiPtr, *bjPtr;    
00157         
00158         // if the matrix has not been factored already factor it into U^t D U
00159         // storing D^-1 in invD as we go
00160 
00161         double a00 = theSOE->A[0];
00162         if (a00 <= 0.0) {
00163           opserr << "ProfileSPDLinDirectSolver::solve() - ";
00164           opserr << " aii < 0 (i, aii): (0,0)\n"; 
00165           return(-2);
00166         }    
00167         
00168         invD[0] = 1.0/theSOE->A[0];     
00169         
00170         // for every col across 
00171         for (int i=1; i<theSize; i++) {
00172 
00173             int rowitop = RowTop[i];
00174             ajiPtr = topRowPtr[i];
00175 
00176             for (int j=rowitop; j<i; j++) {
00177                 double tmp = *ajiPtr;
00178                 int rowjtop = RowTop[j];
00179 
00180                 if (rowitop > rowjtop) {
00181 
00182                     akjPtr = topRowPtr[j] + (rowitop-rowjtop);
00183                     akiPtr = topRowPtr[i];
00184 
00185                     for (int k=rowitop; k<j; k++) 
00186                         tmp -= *akjPtr++ * *akiPtr++ ;
00187 
00188                     *ajiPtr++ = tmp;
00189                 }
00190                 else {
00191                     akjPtr = topRowPtr[j];
00192                     akiPtr = topRowPtr[i] + (rowjtop-rowitop);
00193 
00194                     for (int k=rowjtop; k<j; k++) 
00195                         tmp -= *akjPtr++ * *akiPtr++ ;
00196 
00197                     *ajiPtr++ = tmp;
00198                 }
00199             }
00200 
00201             /* now form i'th col of [U] and determine [dii] */
00202 
00203             double aii = theSOE->A[theSOE->iDiagLoc[i] -1]; // FORTRAN ARRAY INDEXING
00204             ajiPtr = topRowPtr[i];
00205             double *bjPtr  = &X[rowitop];  
00206             double tmp = 0;         
00207             
00208             for (int jj=rowitop; jj<i; jj++) {
00209                 double aji = *ajiPtr;
00210                 double lij = aji * invD[jj];
00211                 tmp -= lij * *bjPtr++;          
00212                 *ajiPtr++ = lij;
00213                 aii = aii - lij*aji;
00214             }
00215             
00216             // check that the diag > the tolerance specified
00217             if (aii == 0.0) {
00218                 opserr << "ProfileSPDLinDirectSolver::solve() - ";
00219                 opserr << " aii < 0 (i, aii): (" << i << ", " << aii << ")\n"; 
00220                 return(-2);
00221             }
00222             if (fabs(aii) <= minDiagTol) {
00223                 opserr << "ProfileSPDLinDirectSolver::solve() - ";
00224                 opserr << " aii < minDiagTol (i, aii): (" << i;
00225                 opserr << ", " << aii << ")\n"; 
00226                 return(-2);
00227             }           
00228             invD[i] = 1.0/aii; 
00229             X[i] += tmp;            
00230         }
00231 
00232         theSOE->isAfactored = true;
00233         theSOE->numInt = 0;
00234         
00235         
00236         // divide by diag term 
00237         bjPtr = X; 
00238         double *aiiPtr = invD;
00239         for (int j=0; j<theSize; j++) 
00240             *bjPtr++ = *aiiPtr++ * X[j];
00241 
00242 
00243         // now do the back substitution storing result in X
00244         for (int k=(theSize-1); k>0; k--) {
00245 
00246             int rowktop = RowTop[k];
00247             double bk = X[k];
00248             double *ajiPtr = topRowPtr[k];              
00249 
00250             for (int j=rowktop; j<k; j++) 
00251                 X[j] -= *ajiPtr++ * bk;
00252         }               
00253     }
00254 
00255     else {
00256 
00257         // JUST DO SOLVE
00258 
00259         // do forward substitution 
00260         for (int i=1; i<theSize; i++) {
00261             
00262             int rowitop = RowTop[i];        
00263             double *ajiPtr = topRowPtr[i];
00264             double *bjPtr  = &X[rowitop];  
00265             double tmp = 0;         
00266             
00267             for (int j=rowitop; j<i; j++) 
00268                 tmp -= *ajiPtr++ * *bjPtr++; 
00269             
00270             X[i] += tmp;
00271         }
00272 
00273         // divide by diag term 
00274         double *bjPtr = X; 
00275         double *aiiPtr = invD;
00276         for (int j=0; j<theSize; j++) 
00277             *bjPtr++ = *aiiPtr++ * X[j];
00278 
00279 
00280         // now do the back substitution storing result in X
00281         for (int k=(theSize-1); k>0; k--) {
00282 
00283             int rowktop = RowTop[k];
00284             double bk = X[k];
00285             double *ajiPtr = topRowPtr[k];              
00286 
00287             for (int j=rowktop; j<k; j++) 
00288                 X[j] -= *ajiPtr++ * bk;
00289         }        
00290     }    
00291     
00292     /*
00293     opserr << "BBBB " << theSOE->getB();
00294     opserr << "XXXX " << theSOE->getX();
00295     */
00296     
00297     return 0;
00298 }
00299 
00300 double
00301 ProfileSPDLinDirectSolver::getDeterminant(void) 
00302 {
00303    int theSize = theSOE->size;
00304    double determinant = 1.0;
00305    for (int i=0; i<theSize; i++)
00306      determinant *= invD[i];
00307    determinant = 1.0/determinant;
00308    return determinant;
00309 }
00310 
00311 int 
00312 ProfileSPDLinDirectSolver::setProfileSOE(ProfileSPDLinSOE &theNewSOE)
00313 {
00314     if (theSOE != 0) {
00315         opserr << "ProfileSPDLinDirectSolver::setProfileSOE() - ";
00316         opserr << " has already been called \n";        
00317         return -1;
00318     }
00319     
00320     theSOE = &theNewSOE;
00321     return 0;
00322 }
00323         
00324 
00325 int 
00326 ProfileSPDLinDirectSolver::factor(int n)
00327 {
00328 
00329     // check for quick returns
00330     if (theSOE == 0) {
00331         opserr << "ProfileSPDLinDirectSolver::factor: ";
00332         opserr << " - No ProfileSPDSOE has been assigned\n";
00333         return -1;
00334     }
00335 
00336     int theSize = theSOE->size;    
00337     if (n > theSize) {
00338         opserr << "ProfileSPDLinDirectSolver::factor: ";
00339         opserr << " - n " << n << " greater than size of system" << theSize << endln;
00340         return -1;
00341     }
00342 
00343     if (theSize == 0 || n == 0)
00344         return 0;
00345 
00346 
00347     // set some pointers
00348     if (theSOE->isAfactored == false)  {
00349 
00350         // FACTOR & SOLVE
00351         double *ajiPtr, *akjPtr, *akiPtr;    
00352         
00353         // if the matrix has not been factored already factor it into U^t D U
00354         // storing D^-1 in invD as we go
00355     
00356         invD[0] = 1.0/theSOE->A[0];     
00357         
00358         // for every col across 
00359         for (int i=1; i<n; i++) {
00360 
00361             int rowitop = RowTop[i];
00362             ajiPtr = topRowPtr[i];
00363 
00364             for (int j=rowitop; j<i; j++) {
00365                 double tmp = *ajiPtr;
00366                 int rowjtop = RowTop[j];
00367 
00368                 if (rowitop > rowjtop) {
00369 
00370                     akjPtr = topRowPtr[j] + (rowitop-rowjtop);
00371                     akiPtr = topRowPtr[i];
00372 
00373                     for (int k=rowitop; k<j; k++) 
00374                         tmp -= *akjPtr++ * *akiPtr++ ;
00375 
00376                     *ajiPtr++ = tmp;
00377                 }
00378                 else {
00379                     akjPtr = topRowPtr[j];
00380                     akiPtr = topRowPtr[i] + (rowjtop-rowitop);
00381 
00382                     for (int k=rowjtop; k<j; k++) 
00383                         tmp -= *akjPtr++ * *akiPtr++ ;
00384 
00385                     *ajiPtr++ = tmp;
00386                 }
00387             }
00388 
00389             /* now form i'th col of [U] and determine [dii] */
00390 
00391             double aii = theSOE->A[theSOE->iDiagLoc[i] -1]; // FORTRAN ARRAY INDEXING
00392             ajiPtr = topRowPtr[i];
00393             
00394             for (int jj=rowitop; jj<i; jj++) {
00395                 double aji = *ajiPtr;
00396                 double lij = aji * invD[jj];
00397                 *ajiPtr++ = lij;
00398                 aii = aii - lij*aji;
00399             }
00400             
00401             // check that the diag > the tolerance specified
00402             if (aii <= 0.0) {
00403                 opserr << "ProfileSPDLinDirectSolver::solve() - ";
00404                 opserr << " aii < 0 (i, aii): (" << i << ", " << aii << ")\n"; 
00405                 return(-2);
00406             }
00407             if (aii <= minDiagTol) {
00408                 opserr << "ProfileSPDLinDirectSolver::solve() - ";
00409                 opserr << " aii < minDiagTol (i, aii): (" << i;
00410                 opserr << ", " << aii << ")\n"; 
00411                 return(-2);
00412             }           
00413             invD[i] = 1.0/aii; 
00414         }
00415 
00416         theSOE->isAfactored = true;
00417         theSOE->numInt = n;
00418         
00419     }   
00420     return 0;
00421 }
00422 
00423 
00424 /*
00425     double *ajiPtr, *akjPtr, *akiPtr, *bjPtr;    
00426         
00427     // if the matrix has not been factored already factor it into U^t D U
00428     // storing D^-1 in invD as we go
00429     
00430     if (theSOE->isAfactored == false) {
00431         
00432         invD[0] = 1.0/theSOE->A[0];     
00433         
00434         // for every col across 
00435         for (int i=1; i<n; i++) {
00436 
00437             int rowitop = RowTop[i];
00438             ajiPtr = topRowPtr[i];
00439 
00440             for (int j=rowitop; j<i; j++) {
00441                 double tmp = *ajiPtr;
00442                 int rowjtop = RowTop[j];
00443 
00444                 if (rowitop > rowjtop) {
00445 
00446                     akjPtr = topRowPtr[j] + (rowitop-rowjtop);
00447                     akiPtr = topRowPtr[i];
00448 
00449                     for (int k=rowitop; k<j; k++) 
00450                         tmp -= *akjPtr++ * *akiPtr++ ;
00451 
00452                     *ajiPtr++ = tmp;
00453                 }
00454                 else {
00455                     akjPtr = topRowPtr[j];
00456                     akiPtr = topRowPtr[i] + (rowjtop-rowitop);
00457 
00458                     for (int k=rowjtop; k<j; k++) 
00459                         tmp -= *akjPtr++ * *akiPtr++ ;
00460 
00461                     *ajiPtr++ = tmp;
00462                 }
00463             }
00464 
00465             // now form i'th col of [U] and determine [dii] 
00466 
00467             double aii = theSOE->A[theSOE->iDiagLoc[i] -1]; // FORTRAN ARRAY INDEXING
00468             ajiPtr = topRowPtr[i];
00469             
00470             for (int jj=rowitop; jj<i; jj++) {
00471                 double aji = *ajiPtr;
00472                 double lij = aji * invD[jj];
00473                 *ajiPtr++ = lij;
00474                 aii = aii - lij*aji;
00475             }
00476             
00477             // check that the diag > the tolerance specified
00478             if (aii <= 0.0)     return(-2);
00479             if (aii <= minDiagTol) return(-1);
00480             invD[i] = 1.0/aii; 
00481         }
00482     }
00483     
00484     theSOE->isAfactored = true;
00485     if (n == theSize)
00486         theSOE->numInt = 0;
00487     else
00488         theSOE->numInt = n;
00489     
00490     return 0;
00491 }
00492 */
00493 
00494 int
00495 ProfileSPDLinDirectSolver::sendSelf(int cTag,
00496                                     Channel &theChannel)
00497 {
00498     return 0;
00499 }
00500 
00501 
00502 int 
00503 ProfileSPDLinDirectSolver::recvSelf(int cTag,
00504                                     Channel &theChannel, 
00505                                     FEM_ObjectBroker &theBroker)
00506 {
00507     return 0;
00508 }
00509 
00510 

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