|
Stratimikos Package Browser (Single Doxygen Collection)
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Stratimikos: Thyra-based strategies for linear solvers 00005 // Copyright (2006) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 // @HEADER 00041 00042 #include "Thyra_AztecOOLinearOpWithSolve.hpp" 00043 #include "Thyra_LinearOpWithSolveHelpers.hpp" 00044 #include "Thyra_EpetraThyraWrappers.hpp" 00045 #include "Thyra_EpetraOperatorWrapper.hpp" 00046 #include "Teuchos_BLAS_types.hpp" 00047 #include "Teuchos_TimeMonitor.hpp" 00048 #include "Teuchos_Time.hpp" 00049 #include "Teuchos_implicit_cast.hpp" 00050 00051 00052 namespace { 00053 00054 00055 inline 00056 Teuchos::ETransp convert( Thyra::EOpTransp trans_in ) 00057 { 00058 Teuchos::ETransp trans_out; 00059 switch(trans_in) { 00060 case Thyra::NOTRANS: 00061 trans_out = Teuchos::NO_TRANS; 00062 break; 00063 case Thyra::TRANS: 00064 trans_out = Teuchos::TRANS; 00065 break; 00066 default: 00067 TEUCHOS_TEST_FOR_EXCEPT(true); // Should never get here! 00068 } 00069 return trans_out; 00070 } 00071 00072 00073 // This class sets some solve instance specific state and then sets it back to 00074 // the default state on destruction. But using the destructor to unset the 00075 // state we can be sure that the state is rest correctly even if an exception 00076 // is thrown. 00077 class SetAztecSolveState { 00078 public: 00079 SetAztecSolveState( 00080 const Teuchos::RCP<AztecOO> &aztecSolver, 00081 const Teuchos::RCP<Teuchos::FancyOStream> &fancyOStream, 00082 const Teuchos::EVerbosityLevel verbLevel, 00083 const Thyra::SolveMeasureType &solveMeasureType 00084 ); 00085 ~SetAztecSolveState(); 00086 private: 00087 Teuchos::RCP<AztecOO> aztecSolver_; 00088 Teuchos::RCP<Teuchos::FancyOStream> fancyOStream_; 00089 Teuchos::EVerbosityLevel verbLevel_; 00090 int outputFrequency_; 00091 int convergenceTest_; 00092 SetAztecSolveState(); // Not defined and not to be called! 00093 }; 00094 00095 00096 SetAztecSolveState::SetAztecSolveState( 00097 const Teuchos::RCP<AztecOO> &aztecSolver, 00098 const Teuchos::RCP<Teuchos::FancyOStream> &fancyOStream, 00099 const Teuchos::EVerbosityLevel verbLevel, 00100 const Thyra::SolveMeasureType &solveMeasureType 00101 ) 00102 :aztecSolver_(aztecSolver.assert_not_null()) 00103 ,outputFrequency_(0) 00104 { 00105 00106 // Output state 00107 verbLevel_ = verbLevel; 00108 if ( Teuchos::VERB_NONE != verbLevel_ ) { 00109 if (!is_null(fancyOStream)) { 00110 // AztecOO puts in two tabs before it prints anything. Therefore, 00111 // there is not much that we can do to improve the layout of the 00112 // indentation so just leave it! 00113 fancyOStream_= Teuchos::tab( 00114 fancyOStream.create_weak(), 00115 0, // Don't indent since AztecOO already puts in two tabs (not spaces!) 00116 Teuchos::implicit_cast<std::string>("AZTECOO") 00117 ); 00118 aztecSolver_->SetOutputStream(*fancyOStream_); 00119 aztecSolver_->SetErrorStream(*fancyOStream_); 00120 // Note, above we can not save the current output and error streams 00121 // since AztecOO does not define functions to get them. In the 00122 // future, AztecOO should define these functions if we are to avoid 00123 // treading on each others print statements. However, since the 00124 // AztecOO object is most likely owned by these Thyra wrappers, this 00125 // should not be a problem. 00126 } 00127 } 00128 else { 00129 outputFrequency_ = aztecSolver_->GetAllAztecOptions()[AZ_output]; 00130 aztecSolver_->SetAztecOption(AZ_output,0); 00131 } 00132 00133 // Convergence test 00134 convergenceTest_ = aztecSolver_->GetAztecOption(AZ_conv); 00135 if (solveMeasureType.useDefault()) 00136 { 00137 // Just use the default solve measure type already set! 00138 } 00139 else if ( 00140 solveMeasureType( 00141 Thyra::SOLVE_MEASURE_NORM_RESIDUAL, 00142 Thyra::SOLVE_MEASURE_NORM_RHS 00143 ) 00144 ) 00145 { 00146 aztecSolver_->SetAztecOption(AZ_conv,AZ_rhs); 00147 } 00148 else if ( 00149 solveMeasureType( 00150 Thyra::SOLVE_MEASURE_NORM_RESIDUAL, 00151 Thyra::SOLVE_MEASURE_NORM_INIT_RESIDUAL 00152 ) 00153 ) 00154 { 00155 aztecSolver_->SetAztecOption(AZ_conv,AZ_r0); 00156 } 00157 else { 00158 TEUCHOS_TEST_FOR_EXCEPT("Invalid solve measure type, you should never get here!"); 00159 } 00160 00161 } 00162 00163 00164 SetAztecSolveState::~SetAztecSolveState() 00165 { 00166 00167 // Output state 00168 if ( Teuchos::VERB_NONE != verbLevel_ ) { 00169 if (!is_null(fancyOStream_)) { 00170 aztecSolver_->SetOutputStream(std::cout); 00171 aztecSolver_->SetErrorStream(std::cerr); 00172 *fancyOStream_ << "\n"; 00173 } 00174 } 00175 else { 00176 aztecSolver_->SetAztecOption(AZ_output,outputFrequency_); 00177 } 00178 00179 // Convergence test 00180 aztecSolver_->SetAztecOption(AZ_conv,convergenceTest_); 00181 00182 } 00183 00184 00185 } // namespace 00186 00187 00188 namespace Thyra { 00189 00190 00191 // Constructors/initializers/accessors 00192 00193 00194 AztecOOLinearOpWithSolve::AztecOOLinearOpWithSolve( 00195 const int fwdDefaultMaxIterations_in 00196 ,const double fwdDefaultTol_in 00197 ,const int adjDefaultMaxIterations_in 00198 ,const double adjDefaultTol_in 00199 ,const bool outputEveryRhs_in 00200 ) 00201 :fwdDefaultMaxIterations_(fwdDefaultMaxIterations_in) 00202 ,fwdDefaultTol_(fwdDefaultTol_in) 00203 ,adjDefaultMaxIterations_(adjDefaultMaxIterations_in) 00204 ,adjDefaultTol_(adjDefaultTol_in) 00205 ,outputEveryRhs_(outputEveryRhs_in) 00206 ,isExternalPrec_(false) 00207 ,allowInexactFwdSolve_(false) 00208 ,allowInexactAdjSolve_(false) 00209 ,aztecSolverScalar_(0.0) 00210 {} 00211 00212 00213 void AztecOOLinearOpWithSolve::initialize( 00214 const RCP<const LinearOpBase<double> > &fwdOp 00215 ,const RCP<const LinearOpSourceBase<double> > &fwdOpSrc 00216 ,const RCP<const PreconditionerBase<double> > &prec 00217 ,const bool isExternalPrec_in 00218 ,const RCP<const LinearOpSourceBase<double> > &approxFwdOpSrc 00219 ,const RCP<AztecOO> &aztecFwdSolver 00220 ,const bool allowInexactFwdSolve 00221 ,const RCP<AztecOO> &aztecAdjSolver 00222 ,const bool allowInexactAdjSolve 00223 ,const double aztecSolverScalar 00224 ) 00225 { 00226 #ifdef TEUCHOS_DEBUG 00227 TEUCHOS_TEST_FOR_EXCEPT(fwdOp.get()==NULL); 00228 TEUCHOS_TEST_FOR_EXCEPT(fwdOpSrc.get()==NULL); 00229 TEUCHOS_TEST_FOR_EXCEPT(aztecFwdSolver.get()==NULL); 00230 #endif 00231 fwdOp_ = fwdOp; 00232 fwdOpSrc_ = fwdOpSrc; 00233 isExternalPrec_ = isExternalPrec_in; 00234 prec_ = prec; 00235 approxFwdOpSrc_ = approxFwdOpSrc; 00236 aztecFwdSolver_ = aztecFwdSolver; 00237 allowInexactFwdSolve_ = allowInexactFwdSolve; 00238 aztecAdjSolver_ = aztecAdjSolver; 00239 allowInexactAdjSolve_ = allowInexactAdjSolve; 00240 aztecSolverScalar_ = aztecSolverScalar; 00241 const std::string fwdOpLabel = fwdOp_->getObjectLabel(); 00242 if (fwdOpLabel.length()) 00243 this->setObjectLabel( "lows("+fwdOpLabel+")" ); 00244 } 00245 00246 00247 RCP<const LinearOpSourceBase<double> > 00248 AztecOOLinearOpWithSolve::extract_fwdOpSrc() 00249 { 00250 RCP<const LinearOpSourceBase<double> > 00251 _fwdOpSrc = fwdOpSrc_; 00252 fwdOpSrc_ = Teuchos::null; 00253 return _fwdOpSrc; 00254 } 00255 00256 00257 RCP<const PreconditionerBase<double> > 00258 AztecOOLinearOpWithSolve::extract_prec() 00259 { 00260 RCP<const PreconditionerBase<double> > 00261 _prec = prec_; 00262 prec_ = Teuchos::null; 00263 return _prec; 00264 } 00265 00266 00267 bool AztecOOLinearOpWithSolve::isExternalPrec() const 00268 { 00269 return isExternalPrec_; 00270 } 00271 00272 00273 RCP<const LinearOpSourceBase<double> > 00274 AztecOOLinearOpWithSolve::extract_approxFwdOpSrc() 00275 { 00276 RCP<const LinearOpSourceBase<double> > 00277 _approxFwdOpSrc = approxFwdOpSrc_; 00278 approxFwdOpSrc_ = Teuchos::null; 00279 return _approxFwdOpSrc; 00280 } 00281 00282 00283 void AztecOOLinearOpWithSolve::uninitialize( 00284 RCP<const LinearOpBase<double> > *fwdOp, 00285 RCP<const LinearOpSourceBase<double> > *fwdOpSrc, 00286 RCP<const PreconditionerBase<double> > *prec, 00287 bool *isExternalPrec_inout, 00288 RCP<const LinearOpSourceBase<double> > *approxFwdOpSrc, 00289 RCP<AztecOO> *aztecFwdSolver, 00290 bool *allowInexactFwdSolve, 00291 RCP<AztecOO> *aztecAdjSolver, 00292 bool *allowInexactAdjSolve, 00293 double *aztecSolverScalar 00294 ) 00295 { 00296 if (fwdOp) *fwdOp = fwdOp_; 00297 if (fwdOpSrc) *fwdOpSrc = fwdOpSrc_; 00298 if (prec) *prec = prec_; 00299 if (isExternalPrec_inout) *isExternalPrec_inout = isExternalPrec_; 00300 if (approxFwdOpSrc) *approxFwdOpSrc = approxFwdOpSrc_; 00301 if (aztecFwdSolver) *aztecFwdSolver = aztecFwdSolver_; 00302 if (allowInexactFwdSolve) *allowInexactFwdSolve = allowInexactFwdSolve_; 00303 if (aztecAdjSolver) *aztecAdjSolver = aztecAdjSolver_; 00304 if (allowInexactAdjSolve) *allowInexactAdjSolve = allowInexactAdjSolve_; 00305 if (aztecSolverScalar) *aztecSolverScalar = aztecSolverScalar_; 00306 00307 fwdOp_ = Teuchos::null; 00308 fwdOpSrc_ = Teuchos::null; 00309 prec_ = Teuchos::null; 00310 isExternalPrec_ = false; // Just to make unique 00311 approxFwdOpSrc_ = Teuchos::null; 00312 aztecFwdSolver_ = Teuchos::null; 00313 allowInexactFwdSolve_ = false; 00314 aztecAdjSolver_ = Teuchos::null; 00315 allowInexactAdjSolve_ = false; 00316 aztecSolverScalar_ = 0.0; 00317 } 00318 00319 00320 // Overridden from LinearOpBase 00321 00322 00323 RCP< const VectorSpaceBase<double> > 00324 AztecOOLinearOpWithSolve::range() const 00325 { 00326 return ( fwdOp_.get() ? fwdOp_->range() : Teuchos::null ); 00327 } 00328 00329 00330 RCP< const VectorSpaceBase<double> > 00331 AztecOOLinearOpWithSolve::domain() const 00332 { 00333 return ( fwdOp_.get() ? fwdOp_->domain() : Teuchos::null ); 00334 } 00335 00336 00337 RCP<const LinearOpBase<double> > 00338 AztecOOLinearOpWithSolve::clone() const 00339 { 00340 return Teuchos::null; // Not supported yet but could be 00341 } 00342 00343 00344 // Overridden from Teuchos::Describable 00345 00346 00347 std::string AztecOOLinearOpWithSolve::description() const 00348 { 00349 std::ostringstream oss; 00350 oss << Teuchos::Describable::description(); 00351 if (fwdOp_.get()) { 00352 oss << "{"; 00353 oss << "fwdOp="<<fwdOp_->description()<<""; 00354 oss << "}"; 00355 } 00356 return oss.str(); 00357 } 00358 00359 00360 void AztecOOLinearOpWithSolve::describe( 00361 Teuchos::FancyOStream &out, 00362 const Teuchos::EVerbosityLevel verbLevel 00363 ) const 00364 { 00365 using Teuchos::OSTab; 00366 using Teuchos::typeName; 00367 using Teuchos::describe; 00368 switch(verbLevel) { 00369 case Teuchos::VERB_DEFAULT: 00370 case Teuchos::VERB_LOW: 00371 out << this->description() << std::endl; 00372 break; 00373 case Teuchos::VERB_MEDIUM: 00374 case Teuchos::VERB_HIGH: 00375 case Teuchos::VERB_EXTREME: 00376 { 00377 out 00378 << Teuchos::Describable::description() << "{" 00379 << "rangeDim=" << this->range()->dim() 00380 << ",domainDim="<< this->domain()->dim() << "}\n"; 00381 OSTab tab(out); 00382 if (!is_null(fwdOp_)) { 00383 out << "fwdOp = " << describe(*fwdOp_,verbLevel); 00384 } 00385 if (!is_null(prec_)) { 00386 out << "prec = " << describe(*prec_,verbLevel); 00387 } 00388 if (!is_null(aztecFwdSolver_)) { 00389 if (aztecFwdSolver_->GetUserOperator()) 00390 out 00391 << "Aztec Fwd Op = " 00392 << typeName(*aztecFwdSolver_->GetUserOperator()) << "\n"; 00393 if (aztecFwdSolver_->GetUserMatrix()) 00394 out 00395 << "Aztec Fwd Mat = " 00396 << typeName(*aztecFwdSolver_->GetUserMatrix()) << "\n"; 00397 if (aztecFwdSolver_->GetPrecOperator()) 00398 out 00399 << "Aztec Fwd Prec Op = " 00400 << typeName(*aztecFwdSolver_->GetPrecOperator()) << "\n"; 00401 if (aztecFwdSolver_->GetPrecMatrix()) 00402 out 00403 << "Aztec Fwd Prec Mat = " 00404 << typeName(*aztecFwdSolver_->GetPrecMatrix()) << "\n"; 00405 } 00406 if (!is_null(aztecAdjSolver_)) { 00407 if (aztecAdjSolver_->GetUserOperator()) 00408 out 00409 << "Aztec Adj Op = " 00410 << typeName(*aztecAdjSolver_->GetUserOperator()) << "\n"; 00411 if (aztecAdjSolver_->GetUserMatrix()) 00412 out 00413 << "Aztec Adj Mat = " 00414 << typeName(*aztecAdjSolver_->GetUserMatrix()) << "\n"; 00415 if (aztecAdjSolver_->GetPrecOperator()) 00416 out 00417 << "Aztec Adj Prec Op = " 00418 << typeName(*aztecAdjSolver_->GetPrecOperator()) << "\n"; 00419 if (aztecAdjSolver_->GetPrecMatrix()) 00420 out 00421 << "Aztec Adj Prec Mat = " 00422 << typeName(*aztecAdjSolver_->GetPrecMatrix()) << "\n"; 00423 } 00424 break; 00425 } 00426 default: 00427 TEUCHOS_TEST_FOR_EXCEPT(true); // Should never get here! 00428 } 00429 } 00430 00431 00432 // protected 00433 00434 00435 // Overridden from LinearOpBase 00436 00437 00438 bool AztecOOLinearOpWithSolve::opSupportedImpl(EOpTransp M_trans) const 00439 { 00440 return ::Thyra::opSupported(*fwdOp_,M_trans); 00441 } 00442 00443 00444 void AztecOOLinearOpWithSolve::applyImpl( 00445 const EOpTransp M_trans, 00446 const MultiVectorBase<double> &X, 00447 const Ptr<MultiVectorBase<double> > &Y, 00448 const double alpha, 00449 const double beta 00450 ) const 00451 { 00452 Thyra::apply( *fwdOp_, M_trans, X, Y, alpha, beta ); 00453 } 00454 00455 00456 // Overridden from LinearOpWithSolveBase 00457 00458 00459 bool 00460 AztecOOLinearOpWithSolve::solveSupportsImpl(EOpTransp M_trans) const 00461 { 00462 if (real_trans(M_trans)==NOTRANS) return true; 00463 return (nonnull(aztecAdjSolver_)); 00464 } 00465 00466 00467 bool 00468 AztecOOLinearOpWithSolve::solveSupportsSolveMeasureTypeImpl( 00469 EOpTransp M_trans, const SolveMeasureType& solveMeasureType 00470 ) const 00471 { 00472 if (real_trans(M_trans)==NOTRANS) { 00473 if (solveMeasureType.useDefault()) 00474 { 00475 return true; 00476 } 00477 else if ( 00478 solveMeasureType( 00479 SOLVE_MEASURE_NORM_RESIDUAL, 00480 SOLVE_MEASURE_NORM_RHS 00481 ) 00482 && 00483 allowInexactFwdSolve_ 00484 ) 00485 { 00486 return true; 00487 } 00488 else if ( 00489 solveMeasureType( 00490 SOLVE_MEASURE_NORM_RESIDUAL, 00491 SOLVE_MEASURE_NORM_INIT_RESIDUAL 00492 ) 00493 && 00494 allowInexactFwdSolve_ 00495 ) 00496 { 00497 return true; 00498 } 00499 } 00500 else { 00501 // TRANS 00502 if (aztecAdjSolver_.get()==NULL) 00503 { 00504 return false; 00505 } 00506 else if (solveMeasureType.useDefault()) 00507 { 00508 return true; 00509 } 00510 else if ( 00511 solveMeasureType( 00512 SOLVE_MEASURE_NORM_RESIDUAL, 00513 SOLVE_MEASURE_NORM_RHS 00514 ) 00515 && 00516 allowInexactFwdSolve_ 00517 ) 00518 { 00519 return true; 00520 } 00521 else if ( 00522 solveMeasureType( 00523 SOLVE_MEASURE_NORM_RESIDUAL, 00524 SOLVE_MEASURE_NORM_INIT_RESIDUAL 00525 ) 00526 && 00527 allowInexactFwdSolve_ 00528 ) 00529 { 00530 return true; 00531 } 00532 } 00533 // If you get here then we don't support the solve measure type! 00534 return false; 00535 } 00536 00537 00538 // Overridden from LinearOpWithSolveBase 00539 00540 00541 SolveStatus<double> 00542 AztecOOLinearOpWithSolve::solveImpl( 00543 const EOpTransp M_trans, 00544 const MultiVectorBase<double> &B, 00545 const Ptr<MultiVectorBase<double> > &X, 00546 const Ptr<const SolveCriteria<double> > solveCriteria 00547 ) const 00548 { 00549 00550 using Teuchos::rcp; 00551 using Teuchos::rcpFromRef; 00552 using Teuchos::rcpFromPtr; 00553 using Teuchos::OSTab; 00554 typedef SolveCriteria<double> SC; 00555 typedef SolveStatus<double> SS; 00556 00557 THYRA_FUNC_TIME_MONITOR("Stratimikos: AztecOOLOWS"); 00558 Teuchos::Time totalTimer(""), timer(""); 00559 totalTimer.start(true); 00560 00561 RCP<Teuchos::FancyOStream> out = this->getOStream(); 00562 Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel(); 00563 OSTab tab = this->getOSTab(); 00564 if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE)) 00565 *out << "\nSolving block system using AztecOO ...\n\n"; 00566 00567 // 00568 // Validate input 00569 // 00570 TEUCHOS_ASSERT(this->solveSupportsImpl(M_trans)); 00571 SolveMeasureType solveMeasureType; 00572 if (nonnull(solveCriteria)) { 00573 solveMeasureType = solveCriteria->solveMeasureType; 00574 assertSupportsSolveMeasureType(*this, M_trans, solveMeasureType); 00575 } 00576 00577 // 00578 // Get the transpose argument 00579 // 00580 const EOpTransp aztecOpTransp = real_trans(M_trans); 00581 00582 // 00583 // Get the solver, operator, and preconditioner that we will use 00584 // 00585 RCP<AztecOO> 00586 aztecSolver = ( aztecOpTransp == NOTRANS ? aztecFwdSolver_ : aztecAdjSolver_ ); 00587 const Epetra_Operator 00588 *aztecOp = aztecSolver->GetUserOperator(); 00589 00590 // 00591 // Get the op(...) range and domain maps 00592 // 00593 const Epetra_Map 00594 &opRangeMap = aztecOp->OperatorRangeMap(), 00595 &opDomainMap = aztecOp->OperatorDomainMap(); 00596 00597 // 00598 // Get the convergence criteria 00599 // 00600 double tol = ( aztecOpTransp==NOTRANS ? fwdDefaultTol() : adjDefaultTol() ); 00601 int maxIterations = ( aztecOpTransp==NOTRANS 00602 ? fwdDefaultMaxIterations() : adjDefaultMaxIterations() ); 00603 bool isDefaultSolveCriteria = true; 00604 if (nonnull(solveCriteria)) { 00605 if ( solveCriteria->requestedTol != SC::unspecifiedTolerance() ) { 00606 tol = solveCriteria->requestedTol; 00607 isDefaultSolveCriteria = false; 00608 } 00609 if (nonnull(solveCriteria->extraParameters)) { 00610 maxIterations = solveCriteria->extraParameters->get("Maximum Iterations",maxIterations); 00611 } 00612 } 00613 00614 // 00615 // Get Epetra_MultiVector views of B and X 00616 // 00617 00618 RCP<const Epetra_MultiVector> epetra_B; 00619 RCP<Epetra_MultiVector> epetra_X; 00620 00621 const EpetraOperatorWrapper* opWrapper = 00622 dynamic_cast<const EpetraOperatorWrapper*>(aztecOp); 00623 00624 if (opWrapper == 0) { 00625 epetra_B = get_Epetra_MultiVector(opRangeMap, rcpFromRef(B)); 00626 epetra_X = get_Epetra_MultiVector(opDomainMap, rcpFromPtr(X)); 00627 } 00628 00629 // 00630 // Use AztecOO to solve each RHS one at a time (which is all that I can do anyway) 00631 // 00632 00633 int totalIterations = 0; 00634 SolveStatus<double> solveStatus; 00635 solveStatus.solveStatus = SOLVE_STATUS_CONVERGED; 00636 solveStatus.achievedTol = -1.0; 00637 00638 /* Get the number of columns in the multivector. We use Thyra 00639 * functions rather than Epetra functions to do this, as we 00640 * might not yet have created an Epetra multivector. - KL */ 00641 //const int m = epetra_B->NumVectors(); 00642 const int m = B.domain()->dim(); 00643 00644 for( int j = 0; j < m; ++j ) { 00645 00646 THYRA_FUNC_TIME_MONITOR_DIFF("Stratimikos: AztecOOLOWS:SingleSolve", SingleSolve); 00647 00648 // 00649 // Get Epetra_Vector views of B(:,j) and X(:,j) 00650 // How this is done will depend on whether we have a true Epetra operator 00651 // or we are wrapping a general Thyra operator in an Epetra operator. 00652 // 00653 00654 // We need to declare epetra_x_j as non-const because when we have a phony 00655 // Epetra operator we'll have to copy a thyra vector into it. 00656 RCP<Epetra_Vector> epetra_b_j; 00657 RCP<Epetra_Vector> epetra_x_j; 00658 00659 if (opWrapper == 0) { 00660 epetra_b_j = rcpFromRef(*const_cast<Epetra_Vector*>((*epetra_B)(j))); 00661 epetra_x_j = rcpFromRef(*(*epetra_X)(j)); 00662 } 00663 else { 00664 if (is_null(epetra_b_j)) { 00665 epetra_b_j = rcp(new Epetra_Vector(opRangeMap)); 00666 epetra_x_j = rcp(new Epetra_Vector(opDomainMap)); 00667 } 00668 opWrapper->copyThyraIntoEpetra(*B.col(j), *epetra_b_j); 00669 opWrapper->copyThyraIntoEpetra(*X->col(j), *epetra_x_j); 00670 } 00671 00672 // 00673 // Set the RHS and LHS 00674 // 00675 00676 aztecSolver->SetRHS(&*epetra_b_j); 00677 aztecSolver->SetLHS(&*epetra_x_j); 00678 00679 // 00680 // Solve the linear system 00681 // 00682 timer.start(true); 00683 { 00684 SetAztecSolveState 00685 setAztecSolveState(aztecSolver,out,verbLevel,solveMeasureType); 00686 aztecSolver->Iterate( maxIterations, tol ); 00687 // NOTE: We ignore the returned status but get it below 00688 } 00689 timer.stop(); 00690 00691 // 00692 // Scale the solution 00693 // (Originally, this was at the end of the loop after all columns had been 00694 // processed. It's moved here because we need to do it before copying the 00695 // solution back into a Thyra vector. - KL 00696 // 00697 if (aztecSolverScalar_ != 1.0) 00698 epetra_x_j->Scale(1.0/aztecSolverScalar_); 00699 00700 // 00701 // If necessary, convert the solution back to a non-epetra vector 00702 // 00703 if (opWrapper != 0) { 00704 opWrapper->copyEpetraIntoThyra(*epetra_x_j, X->col(j).ptr()); 00705 } 00706 00707 // 00708 // Set the return solve status 00709 // 00710 00711 const int iterations = aztecSolver->NumIters(); 00712 const double achievedTol = aztecSolver->ScaledResidual(); 00713 const double *AZ_status = aztecSolver->GetAztecStatus(); 00714 std::ostringstream oss; 00715 bool converged = false; 00716 if (AZ_status[AZ_why]==AZ_normal) { oss << "Aztec returned AZ_normal."; converged = true; } 00717 else if (AZ_status[AZ_why]==AZ_param) oss << "Aztec returned AZ_param."; 00718 else if (AZ_status[AZ_why]==AZ_breakdown) oss << "Aztec returned AZ_breakdown."; 00719 else if (AZ_status[AZ_why]==AZ_loss) oss << "Aztec returned AZ_loss."; 00720 else if (AZ_status[AZ_why]==AZ_ill_cond) oss << "Aztec returned AZ_ill_cond."; 00721 else if (AZ_status[AZ_why]==AZ_maxits) oss << "Aztec returned AZ_maxits."; 00722 else oss << "Aztec returned an unknown status?"; 00723 oss << " Iterations = " << iterations << "."; 00724 oss << " Achieved Tolerance = " << achievedTol << "."; 00725 oss << " Total time = " << timer.totalElapsedTime() << " sec."; 00726 if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE) && outputEveryRhs()) 00727 Teuchos::OSTab(out).o() << "j="<<j<<": " << oss.str() << "\n"; 00728 00729 solveStatus.achievedTol = TEUCHOS_MAX(solveStatus.achievedTol, achievedTol); 00730 // Note, achieveTol may actually be greater than tol due to ill conditioning and roundoff! 00731 00732 totalIterations += iterations; 00733 00734 solveStatus.message = oss.str(); 00735 if ( isDefaultSolveCriteria ) { 00736 switch(solveStatus.solveStatus) { 00737 case SOLVE_STATUS_UNKNOWN: 00738 // Leave overall unknown! 00739 break; 00740 case SOLVE_STATUS_CONVERGED: 00741 solveStatus.solveStatus = ( converged ? SOLVE_STATUS_CONVERGED : SOLVE_STATUS_UNCONVERGED ); 00742 break; 00743 case SOLVE_STATUS_UNCONVERGED: 00744 // Leave overall unconverged! 00745 break; 00746 default: 00747 TEUCHOS_TEST_FOR_EXCEPT(true); // Should never get here! 00748 } 00749 } 00750 } 00751 00752 aztecSolver->UnsetLHSRHS(); 00753 00754 // 00755 // Release the Epetra_MultiVector views of X and B 00756 // 00757 epetra_X = Teuchos::null; 00758 epetra_B = Teuchos::null; 00759 00760 // 00761 // Update the overall solve criteria 00762 // 00763 totalTimer.stop(); 00764 SolveStatus<double> overallSolveStatus; 00765 if (isDefaultSolveCriteria) { 00766 overallSolveStatus.solveStatus = SOLVE_STATUS_UNKNOWN; 00767 overallSolveStatus.achievedTol = SS::unknownTolerance(); 00768 } 00769 else { 00770 overallSolveStatus.solveStatus = solveStatus.solveStatus; 00771 overallSolveStatus.achievedTol = solveStatus.achievedTol; 00772 } 00773 std::ostringstream oss; 00774 oss 00775 << "AztecOO solver " 00776 << ( overallSolveStatus.solveStatus==SOLVE_STATUS_CONVERGED ? "converged" : "unconverged" ) 00777 << " on m = "<<m<<" RHSs using " << totalIterations << " cumulative iterations" 00778 << " for an average of " << (totalIterations/m) << " iterations/RHS and" 00779 << " total CPU time of "<<totalTimer.totalElapsedTime()<<" sec."; 00780 overallSolveStatus.message = oss.str(); 00781 00782 // Added these statistics following what was done for Belos 00783 if (overallSolveStatus.extraParameters.is_null()) { 00784 overallSolveStatus.extraParameters = Teuchos::parameterList (); 00785 } 00786 overallSolveStatus.extraParameters->set ("AztecOO/Iteration Count", 00787 totalIterations); 00788 // package independent version of the same 00789 overallSolveStatus.extraParameters->set ("Iteration Count", 00790 totalIterations); 00791 overallSolveStatus.extraParameters->set ("AztecOO/Achieved Tolerance", 00792 overallSolveStatus.achievedTol); 00793 00794 // 00795 // Report the overall time 00796 // 00797 if (out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW)) 00798 *out 00799 << "\nTotal solve time = "<<totalTimer.totalElapsedTime()<<" sec\n"; 00800 00801 return overallSolveStatus; 00802 00803 } 00804 00805 00806 } // end namespace Thyra
1.7.6.1