Thyra_BelosLinearOpWithSolve.hpp

Go to the documentation of this file.
00001 
00002 #ifndef __sun
00003 
00004 #ifndef THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
00005 #define THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
00006 
00007 #include "Thyra_BelosLinearOpWithSolveDecl.hpp"
00008 #include "Teuchos_Time.hpp"
00009 
00010 namespace Thyra {
00011 
00012 namespace PrivateUtilities {
00013 
00014 template<class LP>
00015 class BelosLinearProblemTempBlockSizeSetter {
00016 public:
00017   BelosLinearProblemTempBlockSizeSetter( const Teuchos::RefCountPtr<LP> &lp, const int newBlockSize )
00018     :lp_(lp), oldBlockSize_(lp->GetBlockSize())
00019     {
00020       lp_->SetBlockSize(newBlockSize);
00021     }
00022   ~BelosLinearProblemTempBlockSizeSetter()
00023     {
00024       lp_->SetBlockSize(oldBlockSize_);
00025     }
00026 private:
00027   Teuchos::RefCountPtr<LP> lp_;
00028   int                      oldBlockSize_;
00029   // Not defined and not to be called
00030   BelosLinearProblemTempBlockSizeSetter();
00031   BelosLinearProblemTempBlockSizeSetter(const BelosLinearProblemTempBlockSizeSetter&);
00032   BelosLinearProblemTempBlockSizeSetter& operator=(const BelosLinearProblemTempBlockSizeSetter&);
00033 };
00034 
00035 }
00036 
00037 // Constructors/initializers/accessors
00038 
00039 template<class Scalar>
00040 BelosLinearOpWithSolve<Scalar>::BelosLinearOpWithSolve()
00041   :isExternalPrec_(false)
00042   ,supportSolveUse_(SUPPORT_SOLVE_UNSPECIFIED)
00043   ,defaultTol_(-1.0)
00044 {}
00045 
00046 template<class Scalar>
00047 BelosLinearOpWithSolve<Scalar>::BelosLinearOpWithSolve(
00048   const Teuchos::RefCountPtr<Belos::LinearProblem<Scalar,MV_t,LO_t> >         &lp
00049   ,const bool                                                                 adjustableBlockSize
00050   ,const int                                                                  maxNumberOfKrylovVectors
00051   ,const Teuchos::RefCountPtr<Teuchos::ParameterList>                         &gmresPL
00052   ,const Teuchos::RefCountPtr<Belos::StatusTestResNorm<Scalar,MV_t,LO_t> >    &resNormST
00053   ,const Teuchos::RefCountPtr<Belos::IterativeSolver<Scalar,MV_t,LO_t> >      &iterativeSolver
00054   ,const Teuchos::RefCountPtr<Belos::OutputManager<Scalar> >                  &outputManager
00055   ,const Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >              &fwdOpSrc
00056   ,const Teuchos::RefCountPtr<const PreconditionerBase<Scalar> >              &prec
00057   ,const bool                                                                 isExternalPrec
00058   ,const Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >              &approxFwdOpSrc
00059   ,const ESupportSolveUse                                                     &supportSolveUse
00060   )
00061 {
00062   initialize(
00063     lp,adjustableBlockSize,maxNumberOfKrylovVectors,gmresPL,resNormST,iterativeSolver
00064     ,outputManager,fwdOpSrc,prec,isExternalPrec,approxFwdOpSrc,supportSolveUse
00065     );
00066 }
00067 
00068 template<class Scalar>
00069 void BelosLinearOpWithSolve<Scalar>::initialize(
00070   const Teuchos::RefCountPtr<Belos::LinearProblem<Scalar,MV_t,LO_t> >         &lp
00071   ,const bool                                                                 adjustableBlockSize
00072   ,const int                                                                  maxNumberOfKrylovVectors
00073   ,const Teuchos::RefCountPtr<Teuchos::ParameterList>                         &gmresPL
00074   ,const Teuchos::RefCountPtr<Belos::StatusTestResNorm<Scalar,MV_t,LO_t> >    &resNormST
00075   ,const Teuchos::RefCountPtr<Belos::IterativeSolver<Scalar,MV_t,LO_t> >      &iterativeSolver
00076   ,const Teuchos::RefCountPtr<Belos::OutputManager<Scalar> >                  &outputManager
00077   ,const Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >              &fwdOpSrc
00078   ,const Teuchos::RefCountPtr<const PreconditionerBase<Scalar> >              &prec
00079   ,const bool                                                                 isExternalPrec
00080   ,const Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >              &approxFwdOpSrc
00081   ,const ESupportSolveUse                                                     &supportSolveUse
00082   )
00083 {
00084   this->setLinePrefix("BELOS/T");
00085   // ToDo: Validate input
00086   lp_ = lp;
00087   adjustableBlockSize_ = adjustableBlockSize;
00088   maxNumberOfKrylovVectors_ = maxNumberOfKrylovVectors;
00089   gmresPL_ = gmresPL;
00090   resNormST_ = resNormST;
00091   iterativeSolver_ = iterativeSolver;
00092   outputManager_ = outputManager;
00093   fwdOpSrc_ = fwdOpSrc;
00094   prec_ = prec;
00095   isExternalPrec_ = isExternalPrec;
00096   approxFwdOpSrc_ = approxFwdOpSrc;
00097   supportSolveUse_ = supportSolveUse;
00098   defaultTol_ = resNormST_->GetTolerance(); // We need to remember this!
00099 }
00100 
00101 template<class Scalar>
00102 Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >
00103 BelosLinearOpWithSolve<Scalar>::extract_fwdOpSrc()
00104 {
00105   Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >
00106     _fwdOpSrc = fwdOpSrc_;
00107   fwdOpSrc_ = Teuchos::null;
00108   return _fwdOpSrc;
00109 }
00110 
00111 template<class Scalar>
00112 Teuchos::RefCountPtr<const PreconditionerBase<Scalar> >
00113 BelosLinearOpWithSolve<Scalar>::extract_prec()
00114 {
00115   Teuchos::RefCountPtr<const PreconditionerBase<Scalar> >
00116     _prec = prec_;
00117   prec_ = Teuchos::null;
00118   return _prec;
00119 }
00120 
00121 template<class Scalar>
00122 bool BelosLinearOpWithSolve<Scalar>::isExternalPrec() const
00123 {
00124   return isExternalPrec_;
00125 }
00126 
00127 template<class Scalar>
00128 Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >
00129 BelosLinearOpWithSolve<Scalar>::extract_approxFwdOpSrc()
00130 {
00131   Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >
00132     _approxFwdOpSrc = approxFwdOpSrc_;
00133   approxFwdOpSrc_ = Teuchos::null;
00134   return _approxFwdOpSrc;
00135 }
00136 
00137 template<class Scalar>
00138 ESupportSolveUse BelosLinearOpWithSolve<Scalar>::supportSolveUse() const
00139 {
00140   return supportSolveUse_;
00141 }
00142 
00143 template<class Scalar>
00144 void BelosLinearOpWithSolve<Scalar>::uninitialize(
00145   Teuchos::RefCountPtr<Belos::LinearProblem<Scalar,MV_t,LO_t> >         *lp
00146   ,bool                                                                 *adjustableBlockSize
00147   ,int                                                                  *maxNumberOfKrylovVectors
00148   ,Teuchos::RefCountPtr<Teuchos::ParameterList>                         *gmresPL
00149   ,Teuchos::RefCountPtr<Belos::StatusTestResNorm<Scalar,MV_t,LO_t> >    *resNormST
00150   ,Teuchos::RefCountPtr<Belos::IterativeSolver<Scalar,MV_t,LO_t> >      *iterativeSolver
00151   ,Teuchos::RefCountPtr<Belos::OutputManager<Scalar> >                  *outputManager
00152   ,Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >              *fwdOpSrc
00153   ,Teuchos::RefCountPtr<const PreconditionerBase<Scalar> >              *prec
00154   ,bool                                                                 *isExternalPrec
00155   ,Teuchos::RefCountPtr<const LinearOpSourceBase<Scalar> >              *approxFwdOpSrc
00156   ,ESupportSolveUse                                                     *supportSolveUse
00157   )
00158 {
00159   TEST_FOR_EXCEPT(true); // ToDo: Implement when needed!
00160 }
00161 
00162 // Overridden from LinearOpBase
00163 
00164 template<class Scalar>
00165 Teuchos::RefCountPtr< const VectorSpaceBase<Scalar> >
00166 BelosLinearOpWithSolve<Scalar>::range() const
00167 {
00168   return lp_->GetOperator()->range();
00169 }
00170 
00171 template<class Scalar>
00172 Teuchos::RefCountPtr< const VectorSpaceBase<Scalar> >
00173 BelosLinearOpWithSolve<Scalar>::domain() const
00174 {
00175   return lp_->GetOperator()->domain();
00176 }
00177 
00178 template<class Scalar>
00179 Teuchos::RefCountPtr<const LinearOpBase<Scalar> >
00180 BelosLinearOpWithSolve<Scalar>::clone() const
00181 {
00182   return Teuchos::null; // Not supported yet but could be
00183 }
00184 
00185 // Overridden from Teuchos::Describable
00186 
00187 template<class Scalar>
00188 std::string BelosLinearOpWithSolve<Scalar>::description() const
00189 {
00190   std::ostringstream oss;
00191   oss << "Thyra::BelosLinearOpWithSolve<"<<Teuchos::ScalarTraits<Scalar>::name()<<">";
00192   if(lp_->GetOperator().get()) {
00193     oss << "{";
00194     oss << "iterativeSolver=\'"<<iterativeSolver_->description()<<"\'";
00195     oss << ",fwdOp=\'"<<lp_->GetOperator()->description()<<"\'";
00196     if(lp_->GetLeftPrec().get())
00197       oss << ",leftPrecOp=\'"<<lp_->GetLeftPrec()->description()<<"\'";
00198     if(lp_->GetRightPrec().get())
00199       oss << ",rightPrecOp=\'"<<lp_->GetRightPrec()->description()<<"\'";
00200     oss << "}";
00201   }
00202   // ToDo: Make Belos::IterativeSolver derive from Teuchos::Describable so
00203   // that we can get better information.
00204   return oss.str();
00205 }
00206 
00207 template<class Scalar>
00208 void BelosLinearOpWithSolve<Scalar>::describe(
00209   Teuchos::FancyOStream                &out_arg
00210   ,const Teuchos::EVerbosityLevel      verbLevel
00211   ) const
00212 {
00213   typedef Teuchos::ScalarTraits<Scalar>  ST;
00214   using Teuchos::RefCountPtr;
00215   using Teuchos::FancyOStream;
00216   using Teuchos::OSTab;
00217   using Teuchos::describe;
00218   RefCountPtr<FancyOStream> out = rcp(&out_arg,false);
00219   OSTab tab(out);
00220   switch(verbLevel) {
00221     case Teuchos::VERB_DEFAULT:
00222     case Teuchos::VERB_LOW:
00223       *out << this->description() << std::endl;
00224       break;
00225     case Teuchos::VERB_MEDIUM:
00226     case Teuchos::VERB_HIGH:
00227     case Teuchos::VERB_EXTREME:
00228     {
00229       *out
00230         << "type = \'Thyra::BelosLinearOpWithSolve<" << ST::name() << ">\', "
00231         << "rangeDim = " << this->range()->dim() << ", domainDim = " << this->domain()->dim() << std::endl;
00232       if(lp_->GetOperator().get()) {
00233         OSTab tab(out);
00234         *out
00235           << "iterativeSolver:\n"<<describe(*iterativeSolver_,verbLevel)
00236           << "fwdOp:\n" << describe(*lp_->GetOperator(),verbLevel);
00237         if(lp_->GetLeftPrec().get())
00238           *out << "leftPrecOp:\n"<<describe(*lp_->GetLeftPrec(),verbLevel);
00239         if(lp_->GetRightPrec().get())
00240           *out << "rightPrecOp:\n"<<describe(*lp_->GetRightPrec(),verbLevel);
00241       }
00242       break;
00243     }
00244     default:
00245       TEST_FOR_EXCEPT(true); // Should never get here!
00246   }
00247 }
00248 
00249 // protected
00250 
00251 // Overridden from SingleScalarLinearOpBase
00252 
00253 template<class Scalar>
00254 bool BelosLinearOpWithSolve<Scalar>::opSupported(ETransp M_trans) const
00255 {
00256   return ::Thyra::opSupported(*lp_->GetOperator(),M_trans);
00257 }
00258 
00259 template<class Scalar>
00260 void BelosLinearOpWithSolve<Scalar>::apply(
00261   const ETransp                     M_trans
00262   ,const MultiVectorBase<Scalar>    &X
00263   ,MultiVectorBase<Scalar>          *Y
00264   ,const Scalar                     alpha
00265   ,const Scalar                     beta
00266   ) const
00267 {
00268   ::Thyra::apply(*lp_->GetOperator(),M_trans,X,Y,alpha,beta);
00269 }
00270 
00271 // Overridden from SingleScalarLinearOpWithSolveBase
00272 
00273 template<class Scalar>
00274 bool BelosLinearOpWithSolve<Scalar>::solveSupportsTrans(ETransp M_trans) const
00275 {
00276   if(real_trans(M_trans)==NOTRANS) return true;
00277   return false; // ToDo: Support adjoint solves!
00278 }
00279 
00280 template<class Scalar>
00281 bool BelosLinearOpWithSolve<Scalar>::solveSupportsSolveMeasureType(ETransp M_trans, const SolveMeasureType& solveMeasureType) const
00282 {
00283   if(real_trans(M_trans)==NOTRANS) {
00284     return (
00285       solveMeasureType.useDefault()
00286       ||
00287       (solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS) && resNormST_.get())
00288       );
00289   }
00290   // TRANS
00291   return false; // ToDo: Support adjoint solves!
00292 }
00293 
00294 template<class Scalar>
00295 void BelosLinearOpWithSolve<Scalar>::solve(
00296   const ETransp                         M_trans
00297   ,const MultiVectorBase<Scalar>        &B
00298   ,MultiVectorBase<Scalar>              *X
00299   ,const int                            numBlocks
00300   ,const BlockSolveCriteria<Scalar>     blockSolveCriteria[]
00301   ,SolveStatus<Scalar>                  blockSolveStatus[]
00302   ) const
00303 {
00304   using Teuchos::RefCountPtr;
00305   using Teuchos::rcp;
00306   using Teuchos::FancyOStream;
00307   using Teuchos::OSTab;
00308   typedef Teuchos::ScalarTraits<Scalar> ST;
00309   typedef typename ST::magnitudeType ScalarMag;
00310   Teuchos::Time totalTimer(""), timer("");
00311   totalTimer.start(true);
00312   
00313   TEST_FOR_EXCEPT(numBlocks > 1); // ToDo: Deal with multiple solve criteria later if needed
00314   TEST_FOR_EXCEPT(!this->solveSupportsTrans(M_trans)); // ToDo: Support adjoint solves later!
00315 
00316   const int numRhs = B.domain()->dim();
00317   const int numEquations = B.range()->dim();
00318 
00319   Teuchos::RefCountPtr<Teuchos::FancyOStream>  out = this->getOStream();
00320   Teuchos::EVerbosityLevel                     verbLevel = this->getVerbLevel();
00321   OSTab tab = this->getOSTab();
00322   if(out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE))
00323     *out
00324       << "\nStarting iterations with Belos solver of type \""<<iterativeSolver_->description()<<"\""
00325       << ", #Eqns="<<numEquations<<", #RHSs="<<numRhs<<" ...\n";
00326 
00327   //
00328   // Temporarily reset the blocksize if we are allowed to due so
00329   //
00330   const int currBlockSize = lp_->GetBlockSize();
00331   const int newBlockSize =
00332     ( adjustableBlockSize_
00333       ? TEUCHOS_MIN(numRhs,TEUCHOS_MIN(currBlockSize,numEquations/2))
00334       // Above: Don't add more vectors than are in the RHS and don't add more
00335       // vectors than half the number of equations or orthogonalization will
00336       // fail on the first iteration!
00337       : currBlockSize
00338       // Above: Just use the user-set block size if we are not allowed to
00339       // ajust this!
00340       );
00341   // Note: Above, we may also need to adjust the block size to be an even
00342   // multiple of the number of RHS.  Also, it would be good if
00343   // Belos::LinearProblem itself allowed for dynamic resizing of the block
00344   // size between restarts.
00345   PrivateUtilities::BelosLinearProblemTempBlockSizeSetter<Belos::LinearProblem<Scalar,MV_t,LO_t> >
00346     tempBlockSizeSetter(lp_,newBlockSize);
00347   if(out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE))
00348     *out << "\nAdjusted block size = " << newBlockSize << "\n";
00349   //
00350   // Set the number of Krylov blocks if we are using GMRES!
00351   //
00352   if(gmresPL_.get()) {
00353     const int BlockGmres_length = maxNumberOfKrylovVectors_/newBlockSize; 
00354     gmresPL_->set("Length",BlockGmres_length);
00355     if(out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE))
00356       *out
00357         << "\nAdjusted max number of GMRES Krylov basis blocks (maxNumberOfKrylovVectors/blockSize) = ("
00358         << maxNumberOfKrylovVectors_ << ")/(" << newBlockSize << ") = " << BlockGmres_length << "\n";
00359   }
00360   //
00361   // Set RHS and LHS
00362   //
00363   lp_->Reset(Teuchos::rcp(X,false),Teuchos::rcp(&B,false));
00364   //
00365   // Set the solution criteria
00366   //
00367   SolveMeasureType solveMeasureType;
00368   if(numBlocks==1) {
00369     solveMeasureType = blockSolveCriteria[0].solveCriteria.solveMeasureType;
00370     const ScalarMag requestedTol = blockSolveCriteria[0].solveCriteria.requestedTol;
00371     TEST_FOR_EXCEPT( !( solveMeasureType.useDefault() || solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS) ) );
00372     if( solveMeasureType.useDefault() ) {
00373         resNormST_->ResetTolerance(defaultTol_);
00374     }
00375     else if( solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS) ) {
00376       if( requestedTol != SolveCriteria<Scalar>::unspecifiedTolerance() )
00377         resNormST_->ResetTolerance(requestedTol);
00378       else
00379         resNormST_->ResetTolerance(defaultTol_);
00380       resNormST_->DefineScaleForm(StatusTestResNorm_t::NormOfRHS,Belos::TwoNorm);
00381     }
00382     else {
00383       TEST_FOR_EXCEPT(true); // Should never get there.
00384     }
00385   }
00386   else {
00387     resNormST_->ResetTolerance(defaultTol_);
00388   }
00389   //
00390   // Solve the linear system
00391   //
00392   iterativeSolver_->GetStatusTest()->Reset(); 
00393   iterativeSolver_->Reset();
00394   if(1){
00395     RefCountPtr<FancyOStream>
00396       outUsed =
00397       ( static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE)
00398         ? out
00399         : rcp(new FancyOStream(rcp(new Teuchos::oblackholestream())))
00400         );
00401     outputManager_->SetOStream(outUsed);
00402     Teuchos::OSTab tab(outUsed,1,"BELOS");
00403     iterativeSolver_->Solve();
00404   }
00405   //
00406   // Report the solve status
00407   //
00408   totalTimer.stop();
00409   const Belos::StatusType belosSolveStatus = resNormST_->GetStatus();
00410   const std::vector<ScalarMag>* resNormValues = resNormST_->GetTestValue();
00411   TEST_FOR_EXCEPT(resNormValues==NULL);
00412   const ScalarMag belosAchievedTol = *std::max_element(resNormValues->begin(),resNormValues->end());
00413   TEST_FOR_EXCEPTION(
00414     belosSolveStatus==Belos::Failed || belosSolveStatus==Belos::NaN, CatastrophicSolveFailure
00415     ,"Error, something really bad happened in the Belos solver!"
00416     ); // ToDo: Get Belos to return a more informative error mesage to embed here?
00417   //
00418   ESolveStatus solveStatus = SOLVE_STATUS_UNKNOWN;
00419   ScalarMag    achievedTol = SolveStatus<Scalar>::unknownTolerance();
00420   if(solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)) {
00421     switch(belosSolveStatus) {
00422       case Belos::Unchecked:
00423         solveStatus = SOLVE_STATUS_UNKNOWN;
00424         break;
00425       case Belos::Unconverged:
00426         solveStatus = SOLVE_STATUS_UNCONVERGED;
00427         break;
00428       case Belos::Converged:
00429         solveStatus = SOLVE_STATUS_CONVERGED;
00430         break;
00431       default:
00432         TEST_FOR_EXCEPT(true); // Should never get here!
00433     }
00434     achievedTol = belosAchievedTol;
00435   }
00436   const int iterations = iterativeSolver_->GetNumIters();
00437   //
00438   std::ostringstream ossmessage;
00439   ossmessage
00440     << "The Belos solver of type \""<<iterativeSolver_->description()<<"\" returned a solve status of \""
00441     << toString(belosSolveStatus) << "\" in " << iterations << " iterations and achieved an approximate max tolerance of "
00442     << belosAchievedTol << " with total CPU time of " << totalTimer.totalElapsedTime() << " sec" ;
00443   if(out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE))
00444     *out << "\n" << ossmessage.str() << "\n";
00445   //
00446   if( numBlocks && blockSolveStatus ) {
00447     blockSolveStatus[0].solveStatus = solveStatus;
00448     blockSolveStatus[0].achievedTol = achievedTol;
00449     blockSolveStatus[0].message     = ossmessage.str();
00450   }
00451   if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
00452     *out
00453       << "\nTotal solve time = "<<totalTimer.totalElapsedTime()<<" sec\n";
00454 }
00455 
00456 } // end namespace Thyra
00457 
00458 #endif // THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
00459 
00460 #endif // __sun

Generated on Thu Sep 18 12:30:22 2008 for Belos Package Browser (Single Doxygen Collection) by doxygen 1.3.9.1