|
Stratimikos Package Browser (Single Doxygen Collection) Version of the Day
|
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
1.7.4