Stratimikos Package Browser (Single Doxygen Collection) Version of the Day
Thyra_BelosLinearOpWithSolve_def.hpp
Go to the documentation of this file.
00001 
00002 #ifndef THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
00003 #define THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
00004 
00005 #include "Thyra_BelosLinearOpWithSolve_decl.hpp"
00006 #include "Thyra_GeneralSolveCriteriaBelosStatusTest.hpp"
00007 #include "Thyra_LinearOpWithSolveHelpers.hpp"
00008 #include "Teuchos_DebugDefaultAsserts.hpp"
00009 #include "Teuchos_Assert.hpp"
00010 #include "Teuchos_TimeMonitor.hpp"
00011 
00012 
00013 namespace Thyra {
00014 
00015 
00016 // Constructors/initializers/accessors
00017 
00018 
00019 template<class Scalar>
00020 BelosLinearOpWithSolve<Scalar>::BelosLinearOpWithSolve()
00021   :convergenceTestFrequency_(-1),
00022   isExternalPrec_(false),
00023   supportSolveUse_(SUPPORT_SOLVE_UNSPECIFIED),
00024   defaultTol_(-1.0)
00025 {}
00026 
00027 
00028 template<class Scalar>
00029 void BelosLinearOpWithSolve<Scalar>::initialize(
00030   const RCP<Belos::LinearProblem<Scalar,MV_t,LO_t> > &lp,
00031   const RCP<Teuchos::ParameterList> &solverPL,
00032   const RCP<Belos::SolverManager<Scalar,MV_t,LO_t> > &iterativeSolver,
00033   const RCP<const LinearOpSourceBase<Scalar> > &fwdOpSrc,
00034   const RCP<const PreconditionerBase<Scalar> > &prec,
00035   const bool isExternalPrec,
00036   const RCP<const LinearOpSourceBase<Scalar> > &approxFwdOpSrc,
00037   const ESupportSolveUse &supportSolveUse,
00038   const int convergenceTestFrequency
00039   )
00040 {
00041   this->setLinePrefix("BELOS/T");
00042   // ToDo: Validate input
00043   lp_ = lp;
00044   solverPL_ = solverPL;
00045   iterativeSolver_ = iterativeSolver;
00046   fwdOpSrc_ = fwdOpSrc;
00047   prec_ = prec;
00048   isExternalPrec_ = isExternalPrec;
00049   approxFwdOpSrc_ = approxFwdOpSrc;
00050   supportSolveUse_ = supportSolveUse;
00051   convergenceTestFrequency_ = convergenceTestFrequency;
00052   // Check if "Convergence Tolerance" is in the solver parameter list.  If
00053   // not, use the default from the solver.
00054   if ( !is_null(solverPL_) ) {
00055     if (solverPL_->isParameter("Convergence Tolerance")) {
00056       defaultTol_ = solverPL_->get<double>("Convergence Tolerance");
00057     }
00058   }
00059   else {
00060     RCP<const Teuchos::ParameterList> defaultPL =
00061       iterativeSolver->getValidParameters();
00062     defaultTol_ = defaultPL->get<double>("Convergence Tolerance");
00063   }
00064 }
00065 
00066 
00067 template<class Scalar>
00068 RCP<const LinearOpSourceBase<Scalar> >
00069 BelosLinearOpWithSolve<Scalar>::extract_fwdOpSrc()
00070 {
00071   RCP<const LinearOpSourceBase<Scalar> >
00072     _fwdOpSrc = fwdOpSrc_;
00073   fwdOpSrc_ = Teuchos::null;
00074   return _fwdOpSrc;
00075 }
00076 
00077 
00078 template<class Scalar>
00079 RCP<const PreconditionerBase<Scalar> >
00080 BelosLinearOpWithSolve<Scalar>::extract_prec()
00081 {
00082   RCP<const PreconditionerBase<Scalar> >
00083     _prec = prec_;
00084   prec_ = Teuchos::null;
00085   return _prec;
00086 }
00087 
00088 
00089 template<class Scalar>
00090 bool BelosLinearOpWithSolve<Scalar>::isExternalPrec() const
00091 {
00092   return isExternalPrec_;
00093 }
00094 
00095 
00096 template<class Scalar>
00097 RCP<const LinearOpSourceBase<Scalar> >
00098 BelosLinearOpWithSolve<Scalar>::extract_approxFwdOpSrc()
00099 {
00100   RCP<const LinearOpSourceBase<Scalar> >
00101     _approxFwdOpSrc = approxFwdOpSrc_;
00102   approxFwdOpSrc_ = Teuchos::null;
00103   return _approxFwdOpSrc;
00104 }
00105 
00106 
00107 template<class Scalar>
00108 ESupportSolveUse BelosLinearOpWithSolve<Scalar>::supportSolveUse() const
00109 {
00110   return supportSolveUse_;
00111 }
00112 
00113 
00114 template<class Scalar>
00115 void BelosLinearOpWithSolve<Scalar>::uninitialize(
00116   RCP<Belos::LinearProblem<Scalar,MV_t,LO_t> > *lp,
00117   RCP<Teuchos::ParameterList> *solverPL,
00118   RCP<Belos::SolverManager<Scalar,MV_t,LO_t> > *iterativeSolver,
00119   RCP<const LinearOpSourceBase<Scalar> > *fwdOpSrc,
00120   RCP<const PreconditionerBase<Scalar> > *prec,
00121   bool *isExternalPrec,
00122   RCP<const LinearOpSourceBase<Scalar> > *approxFwdOpSrc,
00123   ESupportSolveUse *supportSolveUse
00124   )
00125 {
00126   if (lp) *lp = lp_;
00127   if (solverPL) *solverPL = solverPL_;
00128   if (iterativeSolver) *iterativeSolver = iterativeSolver_;
00129   if (fwdOpSrc) *fwdOpSrc = fwdOpSrc_;
00130   if (prec) *prec = prec_;
00131   if (isExternalPrec) *isExternalPrec = isExternalPrec_;
00132   if (approxFwdOpSrc) *approxFwdOpSrc = approxFwdOpSrc_;
00133   if (supportSolveUse) *supportSolveUse = supportSolveUse_;
00134 
00135   lp_ = Teuchos::null;
00136   solverPL_ = Teuchos::null;
00137   iterativeSolver_ = Teuchos::null;
00138   fwdOpSrc_ = Teuchos::null;
00139   prec_ = Teuchos::null;
00140   isExternalPrec_ = false;
00141   approxFwdOpSrc_ = Teuchos::null;
00142   supportSolveUse_ = SUPPORT_SOLVE_UNSPECIFIED;
00143 }
00144 
00145 
00146 // Overridden from LinearOpBase
00147 
00148 
00149 template<class Scalar>
00150 RCP< const VectorSpaceBase<Scalar> >
00151 BelosLinearOpWithSolve<Scalar>::range() const
00152 {
00153   if (!is_null(lp_))
00154     return lp_->getOperator()->range();
00155   return Teuchos::null;
00156 }
00157 
00158 
00159 template<class Scalar>
00160 RCP< const VectorSpaceBase<Scalar> >
00161 BelosLinearOpWithSolve<Scalar>::domain() const
00162 {
00163   if (!is_null(lp_))
00164     return lp_->getOperator()->domain();
00165   return Teuchos::null;
00166 }
00167 
00168 
00169 template<class Scalar>
00170 RCP<const LinearOpBase<Scalar> >
00171 BelosLinearOpWithSolve<Scalar>::clone() const
00172 {
00173   return Teuchos::null; // Not supported yet but could be
00174 }
00175 
00176 
00177 // Overridden from Teuchos::Describable
00178 
00179 
00180 template<class Scalar>
00181 std::string BelosLinearOpWithSolve<Scalar>::description() const
00182 {
00183   std::ostringstream oss;
00184   oss << Teuchos::Describable::description();
00185   if ( !is_null(lp_) && !is_null(lp_->getOperator()) ) {
00186     oss << "{";
00187     oss << "iterativeSolver=\'"<<iterativeSolver_->description()<<"\'";
00188     oss << ",fwdOp=\'"<<lp_->getOperator()->description()<<"\'";
00189     if (lp_->getLeftPrec().get())
00190       oss << ",leftPrecOp=\'"<<lp_->getLeftPrec()->description()<<"\'";
00191     if (lp_->getRightPrec().get())
00192       oss << ",rightPrecOp=\'"<<lp_->getRightPrec()->description()<<"\'";
00193     oss << "}";
00194   }
00195   // ToDo: Make Belos::SolverManager derive from Teuchos::Describable so
00196   // that we can get better information.
00197   return oss.str();
00198 }
00199 
00200 
00201 template<class Scalar>
00202 void BelosLinearOpWithSolve<Scalar>::describe(
00203   Teuchos::FancyOStream &out_arg,
00204   const Teuchos::EVerbosityLevel verbLevel
00205   ) const
00206 {
00207   typedef Teuchos::ScalarTraits<Scalar> ST;
00208   using Teuchos::FancyOStream;
00209   using Teuchos::OSTab;
00210   using Teuchos::describe;
00211   RCP<FancyOStream> out = rcp(&out_arg,false);
00212   OSTab tab(out);
00213   switch (verbLevel) {
00214     case Teuchos::VERB_DEFAULT:
00215     case Teuchos::VERB_LOW:
00216       *out << this->description() << std::endl;
00217       break;
00218     case Teuchos::VERB_MEDIUM:
00219     case Teuchos::VERB_HIGH:
00220     case Teuchos::VERB_EXTREME:
00221     {
00222       *out
00223         << Teuchos::Describable::description()<< "{"
00224         << "rangeDim=" << this->range()->dim()
00225         << ",domainDim=" << this->domain()->dim() << "}\n";
00226       if (lp_->getOperator().get()) {
00227         OSTab tab(out);
00228         *out
00229           << "iterativeSolver = "<<describe(*iterativeSolver_,verbLevel)
00230           << "fwdOp = " << describe(*lp_->getOperator(),verbLevel);
00231         if (lp_->getLeftPrec().get())
00232           *out << "leftPrecOp = "<<describe(*lp_->getLeftPrec(),verbLevel);
00233         if (lp_->getRightPrec().get())
00234           *out << "rightPrecOp = "<<describe(*lp_->getRightPrec(),verbLevel);
00235       }
00236       break;
00237     }
00238     default:
00239       TEST_FOR_EXCEPT(true); // Should never get here!
00240   }
00241 }
00242 
00243 
00244 // protected
00245 
00246 
00247 // Overridden from LinearOpBase
00248 
00249 
00250 template<class Scalar>
00251 bool BelosLinearOpWithSolve<Scalar>::opSupportedImpl(EOpTransp M_trans) const
00252 {
00253   return ::Thyra::opSupported(*lp_->getOperator(),M_trans);
00254 }
00255 
00256 
00257 template<class Scalar>
00258 void BelosLinearOpWithSolve<Scalar>::applyImpl(
00259   const EOpTransp M_trans,
00260   const MultiVectorBase<Scalar> &X,
00261   const Ptr<MultiVectorBase<Scalar> > &Y,
00262   const Scalar alpha,
00263   const Scalar beta
00264   ) const
00265 {
00266   ::Thyra::apply<Scalar>(*lp_->getOperator(), M_trans, X, Y, alpha, beta);
00267 }
00268 
00269 
00270 // Overridden from LinearOpWithSolveBase
00271 
00272 
00273 template<class Scalar>
00274 bool
00275 BelosLinearOpWithSolve<Scalar>::solveSupportsImpl(EOpTransp M_trans) const
00276 {
00277   return solveSupportsNewImpl(M_trans, Teuchos::null);
00278 }
00279 
00280 
00281 template<class Scalar>
00282 bool
00283 BelosLinearOpWithSolve<Scalar>::solveSupportsNewImpl(EOpTransp transp,
00284   const Ptr<const SolveCriteria<Scalar> > solveCriteria) const
00285 {
00286   // Only support forward solve right now!
00287   if (real_trans(transp)==NOTRANS) return true;
00288   return false; // ToDo: Support adjoint solves!
00289   // Otherwise, Thyra/Belos now supports every solve criteria type that exists
00290   // because of the class Thyra::GeneralSolveCriteriaBelosStatusTest!
00291   return true;
00292 /*
00293   if (real_trans(M_trans)==NOTRANS) {
00294     return (
00295       solveMeasureType.useDefault()
00296       ||
00297       solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)
00298       ||
00299       solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_INIT_RESIDUAL)
00300       );
00301   }
00302 */
00303 }
00304 
00305 
00306 template<class Scalar>
00307 bool
00308 BelosLinearOpWithSolve<Scalar>::solveSupportsSolveMeasureTypeImpl(
00309   EOpTransp M_trans, const SolveMeasureType& solveMeasureType) const
00310 {
00311   SolveCriteria<Scalar> solveCriteria(solveMeasureType, SolveCriteria<Scalar>::unspecifiedTolerance());
00312   return solveSupportsNewImpl(M_trans, Teuchos::constOptInArg(solveCriteria));
00313 }
00314 
00315 
00316 template<class Scalar>
00317 SolveStatus<Scalar>
00318 BelosLinearOpWithSolve<Scalar>::solveImpl(
00319   const EOpTransp M_trans,
00320   const MultiVectorBase<Scalar> &B,
00321   const Ptr<MultiVectorBase<Scalar> > &X,
00322   const Ptr<const SolveCriteria<Scalar> > solveCriteria
00323   ) const
00324 {
00325 
00326   TEUCHOS_FUNC_TIME_MONITOR("BelosLOWS");
00327 
00328   using Teuchos::rcp;
00329   using Teuchos::rcpFromRef;
00330   using Teuchos::rcpFromPtr;
00331   using Teuchos::FancyOStream;
00332   using Teuchos::OSTab;
00333   using Teuchos::describe;
00334   typedef Teuchos::ScalarTraits<Scalar> ST;
00335   typedef typename ST::magnitudeType ScalarMag;
00336   Teuchos::Time totalTimer(""), timer("");
00337   totalTimer.start(true);
00338 
00339   assertSolveSupports(*this, M_trans, solveCriteria);
00340   // 2010/08/22: rabartl: Bug 4915 ToDo: Move the above into the NIV function
00341   // solve(...).
00342 
00343   const int numRhs = B.domain()->dim();
00344   const int numEquations = B.range()->dim();
00345 
00346   const RCP<FancyOStream> out = this->getOStream();
00347   const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00348   OSTab tab = this->getOSTab();
00349   if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_LOW)) {
00350     *out << "\nStarting iterations with Belos:\n";
00351     OSTab tab2(out);
00352     *out << "Using forward operator = " << describe(*fwdOpSrc_->getOp(),verbLevel);
00353     *out << "Using iterative solver = " << describe(*iterativeSolver_,verbLevel);
00354     *out << "With #Eqns="<<numEquations<<", #RHSs="<<numRhs<<" ...\n";
00355   }
00356 
00357   //
00358   // Set RHS and LHS
00359   //
00360 
00361   bool ret = lp_->setProblem( rcpFromPtr(X), rcpFromRef(B) );
00362   TEST_FOR_EXCEPTION(
00363     ret == false, CatastrophicSolveFailure
00364     ,"Error, the Belos::LinearProblem could not be set for the current solve!"
00365     );
00366 
00367   //
00368   // Set the solution criteria
00369   //
00370 
00371   const RCP<Teuchos::ParameterList> tmpPL = Teuchos::parameterList();
00372 
00373   SolveMeasureType solveMeasureType;
00374   RCP<GeneralSolveCriteriaBelosStatusTest<Scalar> > generalSolveCriteriaBelosStatusTest;
00375   if (nonnull(solveCriteria)) {
00376     solveMeasureType = solveCriteria->solveMeasureType;
00377     const ScalarMag requestedTol = solveCriteria->requestedTol;
00378     if (solveMeasureType.useDefault()) {
00379       tmpPL->set("Convergence Tolerance", defaultTol_);
00380     }
00381     else if (solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL, SOLVE_MEASURE_NORM_RHS)) {
00382       if (requestedTol != SolveCriteria<Scalar>::unspecifiedTolerance()) {
00383         tmpPL->set("Convergence Tolerance", requestedTol);
00384       }
00385       else {
00386         tmpPL->set("Convergence Tolerance", defaultTol_);
00387       }
00388       tmpPL->set("Explicit Residual Scaling", "Norm of RHS");
00389     }
00390     else if (solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL, SOLVE_MEASURE_NORM_INIT_RESIDUAL)) {
00391       if (requestedTol != SolveCriteria<Scalar>::unspecifiedTolerance()) {
00392         tmpPL->set("Convergence Tolerance", requestedTol);
00393       }
00394       else {
00395         tmpPL->set("Convergence Tolerance", defaultTol_);
00396       }
00397       tmpPL->set("Explicit Residual Scaling", "Norm of Initial Residual");
00398     }
00399     else {
00400       // Set the most generic (and inefficient) solve criteria
00401       generalSolveCriteriaBelosStatusTest = createGeneralSolveCriteriaBelosStatusTest(
00402         *solveCriteria, convergenceTestFrequency_);
00403       // Set the verbosity level (one level down)
00404       generalSolveCriteriaBelosStatusTest->setOStream(out);
00405       generalSolveCriteriaBelosStatusTest->setVerbLevel(incrVerbLevel(verbLevel, -1));
00406       // Set the default convergence tolerance to always converged to allow
00407       // the above status test to control things.
00408       tmpPL->set("Convergence Tolerance", 1.0);
00409     }
00410   }
00411   else {
00412     // No solveCriteria was even passed in!
00413     tmpPL->set("Convergence Tolerance", defaultTol_);
00414   }
00415 
00416   //
00417   // Reset the blocksize if we adding more vectors than half the number of equations,
00418   // orthogonalization will fail on the first iteration!
00419   //
00420 
00421   RCP<const Teuchos::ParameterList> solverParams = iterativeSolver_->getCurrentParameters();
00422   const int currBlockSize = Teuchos::getParameter<int>(*solverParams, "Block Size");
00423   bool isNumBlocks = false;
00424   int currNumBlocks = 0;
00425   if (Teuchos::isParameterType<int>(*solverParams, "Num Blocks")) {
00426     currNumBlocks = Teuchos::getParameter<int>(*solverParams, "Num Blocks");
00427     isNumBlocks = true;
00428   }
00429   const int newBlockSize = TEUCHOS_MIN(currBlockSize,numEquations/2);
00430   if (nonnull(out)
00431     && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE)
00432     && newBlockSize != currBlockSize)
00433   {
00434     *out << "\nAdjusted block size = " << newBlockSize << "\n";
00435   }
00436   //
00437   tmpPL->set("Block Size",newBlockSize);
00438 
00439   //
00440   // Set the number of Krylov blocks if we are using a GMRES solver, or a solver
00441   // that recognizes "Num Blocks". Otherwise the solver will throw an error!
00442   //
00443 
00444   if (isNumBlocks) {
00445     const int Krylov_length = (currNumBlocks*currBlockSize)/newBlockSize;
00446     tmpPL->set("Num Blocks",Krylov_length);
00447   
00448     if (newBlockSize != currBlockSize) {
00449       if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE))
00450         *out
00451           << "\nAdjusted max number of Krylov basis blocks = " << Krylov_length << "\n";
00452     }
00453   }
00454 
00455   //
00456   // Solve the linear system
00457   //
00458 
00459   Belos::ReturnType belosSolveStatus;
00460   {
00461     RCP<std::ostream>
00462       outUsed =
00463       ( static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE)
00464         ? out
00465         : rcp(new FancyOStream(rcp(new Teuchos::oblackholestream())))
00466         );
00467     Teuchos::OSTab tab(outUsed,1,"BELOS");
00468     tmpPL->set("Output Stream", outUsed);
00469     iterativeSolver_->setParameters(tmpPL);
00470     if (nonnull(generalSolveCriteriaBelosStatusTest)) {
00471       iterativeSolver_->setUserConvStatusTest(generalSolveCriteriaBelosStatusTest);
00472     }
00473     belosSolveStatus = iterativeSolver_->solve();
00474   }
00475 
00476   //
00477   // Report the solve status
00478   //
00479 
00480   totalTimer.stop();
00481 
00482   SolveStatus<Scalar> solveStatus;
00483 
00484   switch (belosSolveStatus) {
00485     case Belos::Unconverged: {
00486       solveStatus.solveStatus = SOLVE_STATUS_UNCONVERGED;
00487       break;
00488     }
00489     case Belos::Converged: {
00490       solveStatus.solveStatus = SOLVE_STATUS_CONVERGED;
00491       if (nonnull(generalSolveCriteriaBelosStatusTest)) {
00492         const ArrayView<const ScalarMag> achievedTol = 
00493           generalSolveCriteriaBelosStatusTest->achievedTol();
00494         solveStatus.achievedTol = ST::zero();
00495         for (Ordinal i = 0; i < achievedTol.size(); ++i) {
00496           solveStatus.achievedTol = std::max(solveStatus.achievedTol, achievedTol[i]);
00497         }
00498       }
00499       else {
00500         solveStatus.achievedTol = tmpPL->get("Convergence Tolerance", defaultTol_);
00501       }
00502       break;
00503     }
00504     TEUCHOS_SWITCH_DEFAULT_DEBUG_ASSERT();
00505   }
00506 
00507   std::ostringstream ossmessage;
00508   ossmessage
00509     << "The Belos solver of type \""<<iterativeSolver_->description()
00510     <<"\" returned a solve status of \""<< toString(solveStatus.solveStatus) << "\""
00511     << " in " << iterativeSolver_->getNumIters() << " iterations"
00512     << " with total CPU time of " << totalTimer.totalElapsedTime() << " sec" ;
00513   if (out.get() && static_cast<int>(verbLevel) >=static_cast<int>(Teuchos::VERB_LOW))
00514     *out << "\n" << ossmessage.str() << "\n";
00515 
00516   solveStatus.message = ossmessage.str();
00517 
00518   if (out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
00519     *out << "\nTotal solve time in Belos = "<<totalTimer.totalElapsedTime()<<" sec\n";
00520 
00521   return solveStatus;
00522 
00523 }
00524 
00525 
00526 } // end namespace Thyra
00527 
00528 
00529 #endif // THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines