Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

GenBiCGStabSmootherImplem.H

Go to the documentation of this file.
00001 /* _______              __
00002   / ___/ /  ___  __ _  / /  ___
00003  / /__/ _ \/ _ \/  ' \/ _ \/ _ \
00004  \___/_//_/\___/_/_/_/_.__/\___/
00005 */
00006 //
00007 // This software is copyright (C) by the Lawrence Berkeley
00008 // National Laboratory.  Permission is granted to reproduce
00009 // this software for non-commercial purposes provided that
00010 // this notice is left intact.
00011 //
00012 // It is acknowledged that the U.S. Government has rights to
00013 // this software under Contract DE-AC03-765F00098 between
00014 // the U.S.  Department of Energy and the University of
00015 // California.
00016 //
00017 // This software is provided as a professional and academic
00018 // contribution for joint exchange. Thus it is experimental,
00019 // is provided ``as is'', with no warranties of any kind
00020 // whatsoever, no support, no promise of updates, or printed
00021 // documentation. By using this software, you acknowledge
00022 // that the Lawrence Berkeley National Laboratory and
00023 // Regents of the University of California shall have no
00024 // liability with respect to the infringement of other
00025 // copyrights by any part of this software.
00026 //
00027 
00028 #ifndef _GENBICGSTABSMOOTHERIMPLEM_H_
00029 #define _GENBICGSTABSMOOTHERIMPLEM_H_
00030 
00031 #include "LayoutIterator.H"
00032 
00033 template <class T>
00034 GenBiCGStabSmoother<T>::GenBiCGStabSmoother()
00035 {
00036   m_maxIter = 23;
00037   m_solverTol = 1.0e-7;
00038   m_small = 1.0e-60;
00039 
00040   m_convergeSmall = 1.0e-2;
00041   // m_convergeSmall = 1.0e-15;
00042   // m_convergeSmall = 1.0e-60;
00043 
00044   m_enableRestart = true;
00045 
00046   m_verbose = false;
00047   // m_verbose = true;
00048 }
00049 
00050 template <class T>
00051 GenBiCGStabSmoother<T>::~GenBiCGStabSmoother()
00052 {
00053 }
00054 
00055 template <class T>
00056 GenBiCGStabSmoother<T>* GenBiCGStabSmoother<T>::newBottomSmoother() const
00057 {
00058   GenBiCGStabSmoother* newsmoother = new GenBiCGStabSmoother();
00059   newsmoother->setVerbose(m_verbose);
00060 
00061   if (newsmoother == NULL)
00062   {
00063     MayDay::Error("Out of Memory in GenBiCGStabSmoother::newBottomSmoother");
00064   }
00065 
00066   return newsmoother;
00067 }
00068 
00069 template <class T>
00070 void GenBiCGStabSmoother<T>::setMaxIter(int a_maxIter)
00071 {
00072   m_maxIter = a_maxIter;
00073 }
00074 
00075 template <class T>
00076 void GenBiCGStabSmoother<T>::setSolverTol(Real a_solverTol)
00077 {
00078   m_solverTol = a_solverTol;
00079 }
00080 
00081 template <class T>
00082 void GenBiCGStabSmoother<T>::setEnableRestart(bool a_enableRestart)
00083 {
00084   m_enableRestart = a_enableRestart;
00085 }
00086 
00087 template <class T>
00088 void GenBiCGStabSmoother<T>::setVerbose(bool a_verbose)
00089 {
00090   m_verbose = a_verbose;
00091 }
00092 
00093 /***********************/
00094 // This does a GSRB Pre/Conditioned BiCGStab on a level
00095 // for the bottom solver.
00096 /***********************/
00097 template <class T>
00098 void GenBiCGStabSmoother<T>::doBottomSmooth(T&              a_phi,
00099                                             const T&        a_rhs,
00100                                             GenSolverOp<T>* a_operatorPtr)
00101 {
00102   bool alreadyRestarted = false;
00103   // if we won't allow resarts, then act like we already have...
00104   if (!m_enableRestart) alreadyRestarted =true;
00105   Real small2 = 1.0e-8;
00106 
00107   T corremf;
00108   a_operatorPtr->defineOpData(corremf);
00109 
00110   T residmf;
00111   a_operatorPtr->defineData(residmf);
00112 
00113   T rtwidmf;
00114   a_operatorPtr->defineData(rtwidmf);
00115 
00116   T shatmf;
00117   a_operatorPtr->defineOpData(shatmf);
00118 
00119   T phatmf;
00120   a_operatorPtr->defineOpData(phatmf);
00121 
00122   T pmf;
00123   a_operatorPtr->defineData(pmf);
00124 
00125   T vmf;
00126   a_operatorPtr->defineData(vmf);
00127 
00128   T tmf;
00129   a_operatorPtr->defineData(tmf);
00130 
00131   a_operatorPtr->setToZero(corremf);
00132   a_operatorPtr->setToZero(residmf);
00133   a_operatorPtr->setToZero(rtwidmf);
00134   a_operatorPtr->setToZero(shatmf);
00135   a_operatorPtr->setToZero(phatmf);
00136   a_operatorPtr->setToZero(pmf);
00137   a_operatorPtr->setToZero(vmf);
00138   a_operatorPtr->setToZero(tmf);
00139 
00140   // compute initial residual
00141   a_operatorPtr->applyOpH(a_phi,residmf);
00142   a_operatorPtr->diff(residmf,a_rhs);
00143   a_operatorPtr->negate(residmf);
00144 
00145   Real initnorm;
00146   Real oldNorm;
00147   Real rnorm;
00148   Real norms;
00149 
00150   // compute residual and rhs norms
00151   // finish is norm(residual)/nrom(rhs) < m_solverTol
00152   initnorm = a_operatorPtr->norm(residmf, 0);
00153   rnorm = initnorm;
00154   oldNorm = initnorm;
00155 
00156   if (m_verbose)
00157   {
00158     pout() << "Bottom Smoother initNorm = " << initnorm << endl;
00159   }
00160 
00161   a_operatorPtr->copy(rtwidmf,residmf);
00162 
00163   Vector<Real> rho;
00164   Vector<Real> alpha;
00165   Vector<Real> omega;
00166 
00167   omega.push_back(0.0);
00168   alpha.push_back(0.0);
00169 
00170   // not sure if this is the right thing to do.
00171   // option 1: if any rhoDots are bad, add in current correction and exit
00172   // option 2: keep going with other components?
00173   bool finished = true;
00174 
00175   if (initnorm > m_small)
00176   {
00177     finished = false;
00178   }
00179 
00180   int iter;
00181   for (iter = 1; iter <= m_maxIter && !finished; iter++)
00182   {
00183     Real rhodot;
00184 
00185     bool badDotProd = false;
00186     rhodot = a_operatorPtr->dotProduct(residmf, rtwidmf);
00187 
00188     if (Abs(rhodot) < m_small)
00189     {
00190       badDotProd = true;
00191     }
00192 
00193     rho.push_back(rhodot);
00194 
00195     if (badDotProd)
00196     {
00197 #if FIXIT
00198       for (dit.begin(); dit.ok(); ++dit)
00199       {
00200         a_phi[dit()].plus(corremf[dit()],0,0,ncomp);
00201       }
00202 #endif
00203 
00204       if (m_verbose)
00205       {
00206         pout() << "BiCGStabSmoother: BadDotProd -- returning!  iter = "
00207                << iter << endl;
00208       }
00209 
00210       return;
00211     }
00212 
00213     // if we're restarting the computation, act as if it was
00214     // the first iteration
00215     if (iter == 1 || alreadyRestarted)
00216     {
00217       a_operatorPtr->copy(pmf,residmf);
00218     }
00219     else
00220     {
00221       Real betaim1 = (rho[iter-1]/rho[iter-2]) * (alpha[iter-1]/omega[iter-1]);
00222       Real omegaim1 = omega[iter-1];
00223 
00224       T temp;
00225       a_operatorPtr->defineData(temp);
00226 
00227       a_operatorPtr->copy(temp,vmf);
00228 
00229       a_operatorPtr->scalarMul(temp,omegaim1);
00230       a_operatorPtr->negate(temp);
00231 
00232       a_operatorPtr->sum(temp,pmf);
00233 
00234       a_operatorPtr->scalarMul(temp,betaim1);
00235       a_operatorPtr->sum(temp,residmf);
00236 
00237       a_operatorPtr->copy(pmf,temp);
00238     } // end if i ==  1 's else
00239 
00240     // solve M(phat) = p(i)
00241 #if FIXIT
00242     a_operatorPtr->levelPreconditioner(phatmf, pmf);
00243 #endif
00244 
00245     // v(i) = A(phat)
00246     a_operatorPtr->applyOpH(phatmf,vmf);
00247 
00248     bool badCorrection = false;
00249     Real denom = a_operatorPtr->dotProduct(vmf, rtwidmf);
00250 
00251     // alpha(i) = rho(i-1)/(rtwid^T v(i))
00252     Real alphai;
00253 
00254     if (Abs(denom) > small2*Abs(rho[iter-1]))
00255     {
00256       alphai = rho[iter-1]/denom;
00257     }
00258     else
00259     {
00260       alphai = 0.0;
00261       badCorrection = true;
00262     }
00263 
00264     alpha.push_back(alphai);
00265 
00266     if (!badCorrection)
00267     {
00268 #if FIXIT
00269       // increment residual and solution
00270       for (dit.begin(); dit.ok(); ++dit)
00271       {
00272         T& rfab = residmf[dit()];
00273         T& vfab = vmf[dit()];
00274         T& phatfab = phatmf[dit()];
00275         T& corrfab = corremf[dit()];
00276 
00277         for (int comp = 0; comp < ncomp; comp++)
00278         {
00279           // increment residual: resid = resid - alpha*v
00280           rfab.plus(vfab,-1.0*alpha[comp][iter],comp,comp,1);
00281 
00282           // increment correction: corr = corr + alpha*phat
00283           corrfab.plus(phatfab,alpha[comp][iter],comp,comp,1);
00284         }
00285 
00286       } // end loop over grids
00287 #endif
00288     } // end if the first correction step is OK
00289     else
00290     {
00291       // if correction was bad, don't increment anything,
00292       // but set residual to zero (forces recomputation of resid)
00293       a_operatorPtr->setToZero(residmf);
00294     }
00295 
00296     // compute residual norm
00297     norms = a_operatorPtr->norm(residmf, 0);
00298 
00299     // check norm of s.
00300     // if small enough, step to end (forces recomputation
00301     // of residual, etc
00302 
00303     bool allDone = true;
00304     if (norms > m_solverTol*initnorm)
00305     {
00306       allDone = false;
00307     }
00308 
00309     // if not "done" here, do second correction step
00310     if (!allDone)
00311     {
00312 
00313       // solve Mshat = s
00314 #if FIXIT
00315       a_operatorPtr->levelPreconditioner(shatmf, residmf);
00316 #endif
00317 
00318       // t = A(shat)
00319       a_operatorPtr->applyOpH(shatmf,tmf);
00320 
00321       // w(i) = tTresid/tTt
00322       Real numerw = a_operatorPtr->dotProduct(tmf, residmf);
00323       Real denomw = a_operatorPtr->dotProduct(tmf, tmf);
00324 
00325       Real omegai = 0.0;
00326 
00327       if (Abs(denomw) > m_small)
00328       {
00329         omegai = numerw/denomw;
00330       }
00331 
00332       omega.push_back(omegai);
00333 
00334       // corr(i) = corr(i-1) + omega(i)*shat
00335       // resid(i) = resid(i) - omega(i)*t
00336 
00337 #if FIXIT
00338       for (dit.begin(); dit.ok(); ++dit)
00339       {
00340         Box fabbox = grids.get(dit());
00341         T& corrfab = corremf[dit()];
00342         T& shatfab = shatmf[dit()];
00343         T& tfab = tmf[dit()];
00344 
00345         T ttemp(fabbox, 1);
00346 
00347         for (int comp = 0; comp < ncomp; comp++)
00348         {
00349           // increment correction: corr = corr+omega*shat
00350           corrfab.plus(shatfab,omega[comp][iter],comp,comp,1);
00351 
00352           // increment residual: resid = resid - omega*t
00353           residmf[dit()].plus(tfab,-1.0*omega[comp][iter],comp,comp,1);
00354         }
00355 
00356       } // end loop over grids
00357 #endif
00358 
00359       // reset this just in case (if we made it this
00360       // far, then we can assume that we're not caught in a
00361       // loop
00362       // (dfm, 5/29/02) actually, don't reset this -- only
00363       // allow one restart.
00364       // alreadyRestarted = false;
00365     } // end second update loop
00366     else
00367     {
00368       // if we skipped second update step, still need to store something
00369       // in omega.  try using 0
00370       omega.push_back(0.0);
00371     }
00372 
00373     // now check residual.
00374     allDone = true;
00375 
00376     rnorm = a_operatorPtr->norm(residmf, 0);
00377 
00378     if (m_verbose && (rnorm > 0))
00379     {
00380       pout() << "BottomSmoother: after " << iter
00381              << " iterations, residnorm = " << rnorm << endl;
00382     }
00383 
00384     if ((rnorm > m_solverTol*initnorm) && (Abs(omega[iter]) > m_small))
00385     {
00386       allDone = false;
00387     }
00388 
00389     // second test is to eliminate solver hanging
00390     allDone = allDone &&
00391               (((rnorm < m_solverTol*initnorm) && (Abs(omega[iter]) < m_small))
00392             || (rnorm > oldNorm*(1.0-m_convergeSmall)));
00393 
00394     oldNorm = rnorm;
00395 
00396     // if residnorm is small enough (or if correction is
00397     // small enough), then recompute residual from scratch
00398     // and check again (to avoid roundoff-drift issues).  if
00399     // we _still_ think we're done, then exit
00400     if (allDone)
00401     {
00402       // recompute residual from scratch -- first increment
00403       // a_phi with correction -- also reset correction to zero
00404       a_operatorPtr->setToZero(corremf);
00405 
00406 #if FIXIT
00407       for (dit.begin(); dit.ok(); ++dit)
00408       {
00409         a_phi[dit()].plus(corremf[dit()],0,0,ncomp);
00410       }
00411 #endif
00412 
00413       a_operatorPtr->applyOpH(a_phi,residmf);
00414       a_operatorPtr->diff(residmf,a_rhs);
00415       a_operatorPtr->negate(residmf);
00416 
00417       // now recompute residual norms and check for convergence
00418       allDone = true;
00419 
00420       rnorm = a_operatorPtr->norm(residmf, 0);
00421 
00422       if (rnorm > m_solverTol*initnorm)
00423       {
00424         allDone = false;
00425       }
00426 
00427       // if we've already restarted and haven't gotten
00428       // anywhere, then we've stalled and should probably
00429       // exit.  also, if newly-computed residual still indicates
00430       // convergence, then we're done.
00431       if (alreadyRestarted || allDone)
00432       {
00433         finished = true;
00434       }
00435       else
00436       {
00437         // otherwise, go back and try again with new residual
00438         if (m_verbose)
00439         {
00440           pout() << "Bottom Smoother -- restarting iterations"
00441                  << endl;
00442         }
00443 #if FIXIT
00444         // also reset \tilde{r}
00445         for (dit.begin(); dit.ok(); ++dit)
00446         {
00447           rtwidmf[dit()].copy(residmf[dit()],0,0,ncomp);
00448         }
00449 #endif
00450 
00451         // try doing this recursively?
00452         // BiCGStabSmoother newSmoother;
00453         // Real newTol = m_solverTol*initnorm[0]/rnorm[0];
00454         // newSmoother.setSolverTol(newTol);
00455         // newSmoother.doBottomSmooth(a_phi, a_rhs, a_operatorPtr);
00456 
00457         // finished = true;
00458         finished = false;
00459 
00460         alreadyRestarted = true;
00461       }
00462 
00463       if (finished && m_verbose)
00464       {
00465         pout() << "Bottom Smoother final Norm = " << rnorm << endl;
00466       }
00467     } // end if we're recomputing the residual
00468   } // end main loop over BiCGStab iterations
00469 
00470   bool converged = true;
00471   if (rnorm > m_solverTol*initnorm) converged = false;
00472 
00473   if (!converged && m_verbose)
00474   {
00475     pout() << "BiCGStabSmoother not Converged!  iter = " << iter << endl;
00476     pout() << " resid/initRes = " << rnorm/initnorm << endl;
00477   }
00478 }
00479 
00480 #endif

Generated on Wed Apr 16 14:31:04 2003 for EBChombo by doxygen1.2.16