Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Thyra_AztecOOLinearOpWithSolve.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines