KrylovNewton.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.11 $
00022 // $Date: 2005/11/29 22:42:41 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/analysis/algorithm/equiSolnAlgo/KrylovNewton.cpp,v $
00024 
00025 // Written: MHS
00026 // Created: June 2001
00027 //
00028 // Description: This file contains the class definition for 
00029 // KrylovNewton.  KrylovNewton is a class which uses a Krylov
00030 // subspace accelerator on the modified Newton method.
00031 // The accelerator is described by Carlson and Miller in
00032 // "Design and Application of a 1D GWMFE Code"
00033 // from SIAM Journal of Scientific Computing (Vol. 19, No. 3,
00034 // pp. 728-765, May 1998)
00035 
00036 #include <KrylovNewton.h>
00037 #include <AnalysisModel.h>
00038 #include <StaticAnalysis.h>
00039 #include <IncrementalIntegrator.h>
00040 #include <LinearSOE.h>
00041 #include <Channel.h>
00042 #include <FEM_ObjectBroker.h>
00043 #include <ConvergenceTest.h>
00044 #include <Matrix.h>
00045 #include <Vector.h>
00046 #include <ID.h>
00047 
00048 // Constructor
00049 KrylovNewton::KrylovNewton(int theTangentToUse, int maxDim)
00050 :EquiSolnAlgo(EquiALGORITHM_TAGS_KrylovNewton),
00051  theTest(0), tangent(theTangentToUse),
00052  v(0), Av(0), AvData(0), rData(0), work(0), lwork(0),
00053  numEqns(0), maxDimension(maxDim)
00054 {
00055   if (maxDimension < 0)
00056     maxDimension = 0;
00057 }
00058 
00059 KrylovNewton::KrylovNewton(ConvergenceTest &theT, int theTangentToUse, int maxDim)
00060 :EquiSolnAlgo(EquiALGORITHM_TAGS_KrylovNewton),
00061  theTest(&theT), tangent(theTangentToUse),
00062  v(0), Av(0), AvData(0), rData(0), work(0), lwork(0),
00063  numEqns(0), maxDimension(maxDim)
00064 {
00065   if (maxDimension < 0)
00066     maxDimension = 0;
00067 }
00068 
00069 // Destructor
00070 KrylovNewton::~KrylovNewton()
00071 {
00072   if (v != 0) {
00073     for (int i = 0; i < maxDimension+1; i++)
00074       delete v[i];
00075     delete [] v;
00076   }
00077 
00078   if (Av != 0) {
00079     for (int i = 0; i < maxDimension+1; i++)
00080       delete Av[i];
00081     delete [] Av;
00082   }
00083 
00084   if (AvData != 0)
00085     delete [] AvData;
00086 
00087   if (rData != 0)
00088     delete [] rData;
00089 
00090   if (work != 0)
00091     delete [] work;
00092 }
00093 
00094 int
00095 KrylovNewton::setConvergenceTest(ConvergenceTest *newTest)
00096 {
00097   theTest = newTest;
00098   return 0;
00099 }
00100 
00101 int 
00102 KrylovNewton::solveCurrentStep(void)
00103 {
00104   // set up some pointers and check they are valid
00105   // NOTE this could be taken away if we set Ptrs as protecetd in superclass
00106   AnalysisModel *theAnaModel = this->getAnalysisModelPtr();
00107   IncrementalIntegrator *theIntegrator = this->getIncrementalIntegratorPtr();
00108   LinearSOE *theSOE = this->getLinearSOEptr();
00109   
00110   if ((theAnaModel == 0) || (theIntegrator == 0) || (theSOE == 0)
00111       || (theTest == 0)){
00112     opserr << "WARNING KrylovNewton::solveCurrentStep() - setLinks() has";
00113     opserr << " not been called - or no ConvergenceTest has been set\n";
00114     return -5;
00115   }     
00116 
00117   // Get size information from SOE
00118   numEqns  = theSOE->getNumEqn();
00119   if (maxDimension > numEqns)
00120     maxDimension = numEqns;
00121 
00122   if (v == 0) {
00123     // Need to allocate an extra vector for "next" update
00124     v = new Vector*[maxDimension+1];
00125     for (int i = 0; i < maxDimension+1; i++)
00126       v[i] = new Vector(numEqns);
00127   }
00128 
00129   if (Av == 0) {
00130     Av = new Vector*[maxDimension+1];
00131     for (int i = 0; i < maxDimension+1; i++)
00132       Av[i] = new Vector(numEqns);
00133   }
00134 
00135   if (AvData == 0)
00136     AvData = new double [maxDimension*numEqns];
00137 
00138   if (rData == 0)
00139     // The LAPACK least squares subroutine overwrites the RHS vector
00140     // with the solution vector ... these vectors are not the same
00141     // size, so we need to use the max size
00142     rData = new double [(numEqns > maxDimension) ? numEqns : maxDimension];
00143 
00144   // Length of work vector should be >= 2*min(numEqns,maxDimension)
00145   // See dgels subroutine documentation
00146   lwork = 2 * ((numEqns < maxDimension) ? numEqns : maxDimension);
00147   
00148   if (work == 0)
00149     work = new double [lwork];
00150 
00151   // Evaluate system residual R(y_0)
00152   if (theIntegrator->formUnbalance() < 0) {
00153     opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00154     opserr << "the Integrator failed in formUnbalance()\n";     
00155     return -2;
00156   }
00157 
00158 
00159   // set itself as the ConvergenceTest objects EquiSolnAlgo
00160   theTest->setEquiSolnAlgo(*this);
00161   if (theTest->start() < 0) {
00162     opserr << "KrylovNewton::solveCurrentStep() -";
00163     opserr << "the ConvergenceTest object failed in start()\n";
00164     return -3;
00165   }
00166   
00167   
00168   // Evaluate system Jacobian J = R'(y)|y_0
00169   if (theIntegrator->formTangent(tangent) < 0){
00170     opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00171     opserr << "the Integrator failed in formTangent()\n";
00172     return -1;
00173   }    
00174 
00175   // Loop counter
00176   int k = 1;
00177 
00178   // Current dimension of Krylov subspace
00179   int dim = 0;
00180 
00181   int result = -1;
00182 
00183   do {
00184 
00185     // Clear the subspace if its dimension has exceeded max
00186     if (dim > maxDimension) {
00187       dim = 0;
00188       if (theIntegrator->formTangent(tangent) < 0){
00189         opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00190         opserr << "the Integrator failed to produce new formTangent()\n";
00191         return -1;
00192       }
00193     }
00194 
00195     // Solve for residual f(y_k) = J^{-1} R(y_k)
00196     if (theSOE->solve() < 0) {
00197       opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00198       opserr << "the LinearSysOfEqn failed in solve()\n";       
00199       return -3;
00200     }
00201 
00202     // Solve least squares A w_{k+1} = r_k
00203     if (this->leastSquares(dim) < 0) {
00204       opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00205       opserr << "the Integrator failed in leastSquares()\n";
00206       return -1;
00207     }               
00208 
00209     // Update system with v_k
00210     if (theIntegrator->update(*(v[dim])) < 0) {
00211       opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00212       opserr << "the Integrator failed in update()\n";  
00213       return -4;
00214     }   
00215 
00216     // Evaluate system residual R(y_k)
00217     if (theIntegrator->formUnbalance() < 0) {
00218       opserr << "WARNING KrylovNewton::solveCurrentStep() -";
00219       opserr << "the Integrator failed in formUnbalance()\n";   
00220       return -2;
00221     }
00222 
00223     // Increase current dimension of Krylov subspace
00224     dim++;
00225 
00226     result = theTest->test();
00227     this->record(k++);
00228 
00229   } while (result == -1);
00230   
00231   if (result == -2) {
00232     opserr << "KrylovNewton::solveCurrentStep() -";
00233     opserr << "the ConvergenceTest object failed in test()\n";
00234     return -3;
00235   }
00236   
00237   // note - if postive result we are returning what the convergence
00238   // test returned which should be the number of iterations
00239   return result;
00240 }
00241 
00242 ConvergenceTest *
00243 KrylovNewton::getConvergenceTest(void)
00244 {
00245   return theTest;
00246 }
00247 
00248 int
00249 KrylovNewton::sendSelf(int cTag, Channel &theChannel)
00250 {
00251   return -1;
00252 }
00253 
00254 int
00255 KrylovNewton::recvSelf(int cTag, Channel &theChannel, 
00256                                            FEM_ObjectBroker &theBroker)
00257 {
00258   return -1;
00259 }
00260 
00261 void
00262 KrylovNewton::Print(OPS_Stream &s, int flag)
00263 {
00264   s << "KrylovNewton";
00265   s << "\n\tMax subspace dimension: " << maxDimension;
00266   s << "\n\tNumber of equations: " << numEqns << endln;
00267 }
00268 
00269 #ifdef _WIN32
00270 
00271 extern "C" int  DGELS(char *T, int *M, int *N, int *NRHS,
00272                       double *A, int *LDA, double *B, int *LDB,
00273                       double *WORK, int *LWORK, int *INFO);
00274 
00275 #else
00276 
00277 extern "C" int dgels_(char *T, int *M, int *N, int *NRHS,
00278                       double *A, int *LDA, double *B, int *LDB,
00279                       double *WORK, int *LWORK, int *INFO);
00280 
00281 #endif
00282 
00283 int
00284 KrylovNewton::leastSquares(int k)
00285 {
00286   LinearSOE *theSOE = this->getLinearSOEptr();  
00287   const Vector &r = theSOE->getX();
00288 
00289   // v_{k+1} = w_{k+1} + q_{k+1}
00290   *(v[k])  = r;
00291   *(Av[k]) = r;
00292 
00293   // Subspace is empty
00294   if (k == 0)
00295     return 0;
00296 
00297   // Compute Av_k = f(y_{k-1}) - f(y_k) = r_{k-1} - r_k
00298   Av[k-1]->addVector(1.0, r, -1.0);
00299 
00300   int i,j;
00301 
00302   // Put subspace vectors into AvData
00303   Matrix A(AvData, numEqns, k);
00304   for (i = 0; i < k; i++) {
00305     Vector &Ai = *(Av[i]);
00306     for (j = 0; j < numEqns; j++)
00307       A(j,i) = Ai(j);
00308   }
00309 
00310   // Put residual vector into rData (need to save r for later!)
00311   Vector B(rData, numEqns);
00312   B = r;
00313   
00314   // No transpose
00315   char *trans = "N";
00316 
00317   // The number of right hand side vectors
00318   int nrhs = 1;
00319 
00320   // Leading dimension of the right hand side vector
00321   int ldb = (numEqns > k) ? numEqns : k;
00322 
00323   // Subroutine error flag
00324   int info = 0;
00325 
00326   // Call the LAPACK least squares subroutine
00327 #ifdef _WIN32
00328   DGELS(trans, &numEqns, &k, &nrhs, AvData, &numEqns, rData, &ldb, work, &lwork, &info);
00329 #else
00330   dgels_(trans, &numEqns, &k, &nrhs, AvData, &numEqns, rData, &ldb, work, &lwork, &info);
00331 #endif
00332 
00333   // Check for error returned by subroutine
00334   if (info < 0) {
00335     opserr << "WARNING KrylovNewton::leastSquares() - \n";
00336     opserr << "error code " << info << " returned by LAPACK dgels\n";
00337     return info;
00338   }
00339   
00340   // Compute the correction vector
00341   double cj;
00342   for (j = 0; j < k; j++) {
00343     
00344     // Solution to least squares is written to rData
00345     cj = rData[j];
00346     
00347     // Compute w_{k+1} = c_1 v_1 + ... + c_k v_k
00348     v[k]->addVector(1.0, *(v[j]), cj);
00349     
00350     // Compute least squares residual q_{k+1} = r_k - (c_1 Av_1 + ... + c_k Av_k)
00351     v[k]->addVector(1.0, *(Av[j]), -cj);
00352   }
00353   
00354   return 0;
00355 }
00356 

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