Belos Version of the Day
BelosSolverFactory.hpp
Go to the documentation of this file.
00001 //@HEADER
00002 // ************************************************************************
00003 //
00004 //                 Belos: Block Linear Solvers Package
00005 //                  Copyright 2004 Sandia Corporation
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
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 Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ************************************************************************
00040 //@HEADER
00041 
00042 #ifndef __Belos_SolverFactory_hpp
00043 #define __Belos_SolverFactory_hpp
00044 
00045 #include <BelosConfigDefs.hpp>
00046 #include <BelosOutputManager.hpp>
00047 #include <BelosSolverManager.hpp>
00048 
00049 #include <BelosBlockGmresSolMgr.hpp>
00050 #include <BelosPseudoBlockGmresSolMgr.hpp>
00051 #include <BelosBlockCGSolMgr.hpp>
00052 #include <BelosPseudoBlockCGSolMgr.hpp>
00053 #include <BelosPseudoBlockStochasticCGSolMgr.hpp>
00054 #include <BelosGCRODRSolMgr.hpp>
00055 #include <BelosRCGSolMgr.hpp>
00056 #include <BelosMinresSolMgr.hpp>
00057 #include <BelosLSQRSolMgr.hpp>
00058 
00059 #include <Teuchos_Array.hpp>
00060 #include <Teuchos_Describable.hpp>
00061 #include <Teuchos_StandardCatchMacros.hpp>
00062 #include <Teuchos_TypeNameTraits.hpp>
00063 
00064 #include <algorithm>
00065 #include <map>
00066 #include <sstream>
00067 #include <stdexcept>
00068 #include <vector>
00069 
00070 namespace Belos {
00071 
00072 namespace details {
00073 
00092 enum EBelosSolverType {
00093   SOLVER_TYPE_BLOCK_GMRES,
00094   SOLVER_TYPE_PSEUDO_BLOCK_GMRES,
00095   SOLVER_TYPE_BLOCK_CG,
00096   SOLVER_TYPE_PSEUDO_BLOCK_CG,
00097   SOLVER_TYPE_GCRODR,
00098   SOLVER_TYPE_RCG,
00099   SOLVER_TYPE_MINRES,
00100   SOLVER_TYPE_LSQR,
00101   SOLVER_TYPE_STOCHASTIC_CG
00102 };
00103 
00104 } // namespace details
00105 
00213 template<class Scalar, class MV, class OP>
00214 class SolverFactory : public Teuchos::Describable {
00215 public:
00222   typedef SolverManager<Scalar, MV, OP> solver_base_type;
00223 
00225   SolverFactory();
00226 
00256   Teuchos::RCP<solver_base_type>
00257   create (const std::string& solverName,
00258           const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
00259 
00265   int numSupportedSolvers () const;
00266 
00272   Teuchos::Array<std::string> supportedSolverNames () const;
00273 
00275   bool isSupported (const std::string& solverName) const;
00276 
00278 
00279 
00281   std::string description() const;
00282 
00288   void describe (Teuchos::FancyOStream& out,
00289                  const Teuchos::EVerbosityLevel verbLevel = Teuchos::Describable::verbLevel_default) const;
00291 
00292 private:
00305   std::map<std::string, std::string> aliasToCanonicalName_;
00306 
00320   std::map<std::string, details::EBelosSolverType> canonicalNameToEnum_;
00321 
00327   void
00328   reviseParameterListForAlias (const std::string& aliasName,
00329                                const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
00330 
00332   Teuchos::Array<std::string> canonicalSolverNames () const;
00333 
00335   Teuchos::Array<std::string> solverNameAliases () const;
00336 };
00337 
00338 
00339 namespace details {
00340 
00359 template<class SolverManagerBaseType, class SolverManagerType>
00360 Teuchos::RCP<SolverManagerBaseType>
00361 makeSolverManagerTmpl (const Teuchos::RCP<Teuchos::ParameterList>& params);
00362 
00381 template<class Scalar, class MV, class OP>
00382 Teuchos::RCP<SolverManager<Scalar, MV, OP> >
00383 makeSolverManagerFromEnum (const EBelosSolverType solverType,
00384                            const Teuchos::RCP<Teuchos::ParameterList>& params)
00385 {
00386   typedef SolverManager<Scalar, MV, OP> base_type;
00387 
00388   switch (solverType) {
00389   case SOLVER_TYPE_BLOCK_GMRES: {
00390     typedef BlockGmresSolMgr<Scalar, MV, OP> impl_type;
00391     return makeSolverManagerTmpl<base_type, impl_type> (params);
00392     break;
00393   }
00394   case SOLVER_TYPE_PSEUDO_BLOCK_GMRES: {
00395     typedef PseudoBlockGmresSolMgr<Scalar, MV, OP> impl_type;
00396     return makeSolverManagerTmpl<base_type, impl_type> (params);
00397     break;
00398   }
00399   case SOLVER_TYPE_BLOCK_CG: {
00400     typedef BlockCGSolMgr<Scalar, MV, OP> impl_type;
00401     return makeSolverManagerTmpl<base_type, impl_type> (params);
00402     break;
00403   }
00404   case SOLVER_TYPE_PSEUDO_BLOCK_CG: {
00405     typedef PseudoBlockCGSolMgr<Scalar, MV, OP> impl_type;
00406     return makeSolverManagerTmpl<base_type, impl_type> (params);
00407     break;
00408   }
00409   case SOLVER_TYPE_GCRODR: {
00410     typedef GCRODRSolMgr<Scalar, MV, OP> impl_type;
00411     return makeSolverManagerTmpl<base_type, impl_type> (params);
00412     break;
00413   }
00414   case SOLVER_TYPE_RCG: {
00415     typedef RCGSolMgr<Scalar, MV, OP> impl_type;
00416     return makeSolverManagerTmpl<base_type, impl_type> (params);
00417     break;
00418   }
00419   case SOLVER_TYPE_MINRES: {
00420     typedef MinresSolMgr<Scalar, MV, OP> impl_type;
00421     return makeSolverManagerTmpl<base_type, impl_type> (params);
00422     break;
00423   }
00424   case SOLVER_TYPE_LSQR: {
00425     typedef LSQRSolMgr<Scalar, MV, OP> impl_type;
00426     return makeSolverManagerTmpl<base_type, impl_type> (params);
00427     break;
00428   }
00429   case SOLVER_TYPE_STOCHASTIC_CG: {
00430     typedef PseudoBlockStochasticCGSolMgr<Scalar, MV, OP> impl_type;
00431     return makeSolverManagerTmpl<base_type, impl_type> (params);
00432   }
00433   default: // Fall through; let the code below handle it.
00434     TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
00435       "Invalid EBelosSolverType enum value " << solverType
00436       << ".  Please report this bug to the Belos developers.");
00437   }
00438 
00439   // Compiler guard.  This may result in a warning on some compilers
00440   // for an unreachable statement, but it will prevent a warning on
00441   // other compilers for a "missing return statement at end of
00442   // non-void function."
00443   return Teuchos::null;
00444 }
00445 
00446 template<class SolverManagerBaseType, class SolverManagerType>
00447 Teuchos::RCP<SolverManagerBaseType>
00448 makeSolverManagerTmpl (const Teuchos::RCP<Teuchos::ParameterList>& params)
00449 {
00450   using Teuchos::ParameterList;
00451   using Teuchos::parameterList;
00452   using Teuchos::RCP;
00453 
00454   RCP<SolverManagerType> solver = rcp (new SolverManagerType);
00455 
00456   // Some solvers may not like to get a null ParameterList.  If params
00457   // is null, replace it with the solver's default parameters.
00458   RCP<ParameterList> pl;
00459   if (params.is_null()) {
00460     pl = parameterList (*solver->getValidParameters());
00461   } else {
00462     pl = params;
00463   }
00464   TEUCHOS_TEST_FOR_EXCEPTION(pl.is_null(), std::logic_error,
00465                              "ParameterList to pass to solver is null.  This "
00466                              "should never happen.  Please report this bug to "
00467                              "the Belos developers.");
00468   solver->setParameters (pl);
00469   return solver;
00470 }
00471 
00472 } // namespace details
00473 
00474 
00475 template<class Scalar, class MV, class OP>
00476 SolverFactory<Scalar, MV, OP>::SolverFactory()
00477 {
00478   aliasToCanonicalName_["GMRES"] = "Pseudoblock GMRES";
00479   // NOTE (mfh 29 Nov 2011) Accessing the flexible capability requires
00480   // setting a parameter in the solver's parameter list.  This affects
00481   // the SolverFactory's interface, since using the "Flexible GMRES"
00482   // alias requires modifying the user's parameter list if necessary.
00483   // This is a good idea because users may not know about the
00484   // parameter, or may have forgotten.
00485   aliasToCanonicalName_["Flexible GMRES"] = "Block GMRES";
00486   aliasToCanonicalName_["CG"] = "Pseudoblock CG";
00487   aliasToCanonicalName_["Stochastic CG"] = "Pseudoblock Stochastic CG";
00488   aliasToCanonicalName_["Recycling CG"] = "RCG";
00489   aliasToCanonicalName_["Recycling GMRES"] = "GCRODR";
00490   // For compatibility with Stratimikos' Belos adapter.
00491   aliasToCanonicalName_["Pseudo Block GMRES"] = "Pseudoblock GMRES";
00492   aliasToCanonicalName_["Pseudo Block CG"] = "Pseudoblock CG";
00493 
00494   // Mapping from canonical solver name (a string) to its
00495   // corresponding enum value.  This mapping is one-to-one.
00496   canonicalNameToEnum_["Block GMRES"] = details::SOLVER_TYPE_BLOCK_GMRES;
00497   canonicalNameToEnum_["Pseudoblock GMRES"] = details::SOLVER_TYPE_PSEUDO_BLOCK_GMRES;
00498   canonicalNameToEnum_["Block CG"] = details::SOLVER_TYPE_BLOCK_CG;
00499   canonicalNameToEnum_["Pseudoblock CG"] = details::SOLVER_TYPE_PSEUDO_BLOCK_CG;
00500   canonicalNameToEnum_["Pseudoblock Stochastic CG"] = details::SOLVER_TYPE_STOCHASTIC_CG;
00501   canonicalNameToEnum_["GCRODR"] = details::SOLVER_TYPE_GCRODR;
00502   canonicalNameToEnum_["RCG"] = details::SOLVER_TYPE_RCG;
00503   canonicalNameToEnum_["MINRES"] = details::SOLVER_TYPE_MINRES;
00504   canonicalNameToEnum_["LSQR"] = details::SOLVER_TYPE_LSQR;
00505 }
00506 
00507 
00508 template<class Scalar, class MV, class OP>
00509 void
00510 SolverFactory<Scalar, MV, OP>::
00511 reviseParameterListForAlias (const std::string& aliasName,
00512                              const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
00513 {
00514   TEUCHOS_TEST_FOR_EXCEPTION(solverParams.is_null(), std::logic_error,
00515     "Belos::SolverFactory::reviseParameterListForAlias: the input "
00516     "ParameterList is supposed to be nonnull.  Please report this "
00517     "bug to the Belos developers.");
00518   if (aliasName == "Flexible GMRES") {
00519     // "Gmres" uses title case in this solver's parameter list.  For
00520     // our alias, we prefer the all-capitals "GMRES" that the
00521     // algorithm's authors (Saad and Schultz) used.
00522     solverParams->set ("Flexible Gmres", true);
00523   }
00524 }
00525 
00526 
00527 template<class Scalar, class MV, class OP>
00528 Teuchos::RCP<typename SolverFactory<Scalar, MV, OP>::solver_base_type>
00529 SolverFactory<Scalar, MV, OP>::
00530 create (const std::string& solverName,
00531         const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
00532 {
00533   // Check whether the given name is an alias.
00534   std::map<std::string, std::string>::const_iterator aliasIter =
00535     aliasToCanonicalName_.find (solverName);
00536   const bool isAnAlias = (aliasIter != aliasToCanonicalName_.end());
00537   const std::string candidateCanonicalName =
00538     isAnAlias ? aliasIter->second : solverName;
00539 
00540   // Get the canonical name.
00541   std::map<std::string, details::EBelosSolverType>::const_iterator canonicalIter =
00542     canonicalNameToEnum_.find (candidateCanonicalName);
00543   const bool validCanonicalName = (canonicalIter != canonicalNameToEnum_.end());
00544 
00545   // Check whether we found a canonical name.  If we didn't and the
00546   // input name is a valid alias, that's a bug.  Otherwise, the input
00547   // name is invalid.
00548   TEUCHOS_TEST_FOR_EXCEPTION(! validCanonicalName && isAnAlias, std::logic_error,
00549     "Valid alias \"" << solverName << "\" has candidate canonical name \""
00550     << candidateCanonicalName << "\", which is not a canonical solver name.  "
00551     "Please report this bug to the Belos developers.");
00552   TEUCHOS_TEST_FOR_EXCEPTION(! validCanonicalName && ! isAnAlias,
00553     std::invalid_argument, "Invalid solver name \"" << solverName << "\".");
00554 
00555   // If the input list is null, we create a new list and use that.
00556   // This is OK because the effect of a null parameter list input is
00557   // to use default parameter values.  Thus, we can always replace a
00558   // null list with an empty list.
00559   Teuchos::RCP<Teuchos::ParameterList> pl =
00560     solverParams.is_null() ? Teuchos::parameterList() : solverParams;
00561 
00562   // Possibly modify the input parameter list as needed.
00563   if (isAnAlias) {
00564     reviseParameterListForAlias (solverName, pl);
00565   }
00566 
00567   return details::makeSolverManagerFromEnum<Scalar, MV, OP> (canonicalIter->second, pl);
00568 }
00569 
00570 
00571 template<class Scalar, class MV, class OP>
00572 std::string
00573 SolverFactory<Scalar, MV, OP>::description() const
00574 {
00575   using Teuchos::TypeNameTraits;
00576   std::ostringstream os;
00577   os << "Belos::SolverFactory<" << TypeNameTraits<Scalar>::name()
00578      << ", " << TypeNameTraits<Scalar>::name()
00579      << ", " << TypeNameTraits<MV>::name()
00580      << ", " << TypeNameTraits<OP>::name()
00581      << ">";
00582   return os.str();
00583 }
00584 
00585 template<class Scalar, class MV, class OP>
00586 void
00587 SolverFactory<Scalar, MV, OP>::
00588 describe (Teuchos::FancyOStream& out,
00589           const Teuchos::EVerbosityLevel verbLevel) const
00590 {
00591   using std::endl;
00592   typedef Teuchos::Array<std::string>::const_iterator iter_type;
00593 
00594   Teuchos::OSTab tab1 (out);
00595   out << this->description();
00596 
00597   // At higher verbosity levels, print out the list of supported solvers.
00598   if (static_cast<int> (verbLevel) > static_cast<int> (Teuchos::VERB_LOW)) {
00599     out << ":" << endl;
00600     Teuchos::OSTab tab2 (out);
00601     out << "Number of supported solvers: " << numSupportedSolvers()
00602         << endl;
00603     out << "Supported canonical solver names:";
00604     {
00605       Teuchos::Array<std::string> names = canonicalSolverNames();
00606       for (iter_type iter = names.begin(); iter != names.end(); ++iter) {
00607         out << *iter;
00608         if (iter + 1 != names.end()) {
00609           out << ", ";
00610         }
00611       }
00612     }
00613     out << "Supported aliases to canonical names:";
00614     {
00615       Teuchos::Array<std::string> names = solverNameAliases();
00616       for (iter_type iter = names.begin(); iter != names.end(); ++iter) {
00617         out << *iter;
00618         if (iter + 1 != names.end()) {
00619           out << ", ";
00620         }
00621       }
00622     }
00623   }
00624 }
00625 
00626 template<class Scalar, class MV, class OP>
00627 int
00628 SolverFactory<Scalar, MV, OP>::numSupportedSolvers () const
00629 {
00630   return static_cast<int> (canonicalNameToEnum_.size());
00631 }
00632 
00633 template<class Scalar, class MV, class OP>
00634 Teuchos::Array<std::string>
00635 SolverFactory<Scalar, MV, OP>::canonicalSolverNames () const
00636 {
00637   Teuchos::Array<std::string> canonicalNames;
00638   typedef std::map<std::string, details::EBelosSolverType>::const_iterator iter_type;
00639   for (iter_type iter = canonicalNameToEnum_.begin();
00640        iter != canonicalNameToEnum_.end(); ++iter) {
00641     canonicalNames.push_back (iter->first);
00642   }
00643   return canonicalNames;
00644 }
00645 
00646 template<class Scalar, class MV, class OP>
00647 Teuchos::Array<std::string>
00648 SolverFactory<Scalar, MV, OP>::solverNameAliases () const
00649 {
00650   Teuchos::Array<std::string> names;
00651   {
00652     typedef std::map<std::string, std::string>::const_iterator iter_type;
00653     for (iter_type iter = aliasToCanonicalName_.begin();
00654          iter != aliasToCanonicalName_.end(); ++iter) {
00655       names.push_back (iter->first);
00656     }
00657   }
00658   return names;
00659 }
00660 
00661 template<class Scalar, class MV, class OP>
00662 Teuchos::Array<std::string>
00663 SolverFactory<Scalar, MV, OP>::supportedSolverNames () const
00664 {
00665   Teuchos::Array<std::string> names;
00666   {
00667     typedef std::map<std::string, std::string>::const_iterator iter_type;
00668     for (iter_type iter = aliasToCanonicalName_.begin();
00669          iter != aliasToCanonicalName_.end(); ++iter) {
00670       names.push_back (iter->first);
00671     }
00672   }
00673   {
00674     typedef std::map<std::string, details::EBelosSolverType>::const_iterator iter_type;
00675     for (iter_type iter = canonicalNameToEnum_.begin();
00676          iter != canonicalNameToEnum_.end(); ++iter) {
00677       names.push_back (iter->first);
00678     }
00679   }
00680   return names;
00681 }
00682 
00683 } // namespace Belos
00684 
00685 #endif // __Belos_SolverFactory_hpp
00686 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines