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 <BelosGCRODRSolMgr.hpp>
00054 #include <BelosRCGSolMgr.hpp>
00055 #include <BelosMinresSolMgr.hpp>
00056 #include <BelosLSQRSolMgr.hpp>
00057 
00058 #include <Teuchos_Array.hpp>
00059 #include <Teuchos_Describable.hpp>
00060 #include <Teuchos_StandardCatchMacros.hpp>
00061 #include <Teuchos_TypeNameTraits.hpp>
00062 
00063 #include <algorithm>
00064 #include <map>
00065 #include <sstream>
00066 #include <stdexcept>
00067 #include <vector>
00068 
00069 namespace Belos {
00070 
00071 namespace details {
00072 
00091 enum EBelosSolverType {
00092   SOLVER_TYPE_BLOCK_GMRES,
00093   SOLVER_TYPE_PSEUDO_BLOCK_GMRES,
00094   SOLVER_TYPE_BLOCK_CG,
00095   SOLVER_TYPE_PSEUDO_BLOCK_CG,
00096   SOLVER_TYPE_GCRODR,
00097   SOLVER_TYPE_RCG,
00098   SOLVER_TYPE_MINRES,
00099   SOLVER_TYPE_LSQR
00100 };
00101 
00102 } // namespace details
00103 
00211 template<class Scalar, class MV, class OP>
00212 class SolverFactory : public Teuchos::Describable {
00213 public:
00220   typedef SolverManager<Scalar, MV, OP> solver_base_type;
00221 
00223   SolverFactory();
00224 
00254   Teuchos::RCP<solver_base_type>
00255   create (const std::string& solverName, 
00256     const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
00257 
00263   int numSupportedSolvers () const;
00264 
00270   Teuchos::Array<std::string> supportedSolverNames () const;
00271 
00273   bool isSupported (const std::string& solverName) const;
00274 
00276 
00277 
00279   std::string description() const;
00280 
00286   void describe (Teuchos::FancyOStream& out, 
00287      const Teuchos::EVerbosityLevel verbLevel = Teuchos::Describable::verbLevel_default) const;
00289 
00290 private:
00303   std::map<std::string, std::string> aliasToCanonicalName_;
00304 
00318   std::map<std::string, details::EBelosSolverType> canonicalNameToEnum_;
00319 
00325   void
00326   reviseParameterListForAlias (const std::string& aliasName,
00327              const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
00328 
00330   Teuchos::Array<std::string> canonicalSolverNames () const;
00331 
00333   Teuchos::Array<std::string> solverNameAliases () const;
00334 }; 
00335 
00336 
00337 namespace details {
00338 
00357 template<class SolverManagerBaseType, class SolverManagerType>
00358 Teuchos::RCP<SolverManagerBaseType>
00359 makeSolverManagerTmpl (const Teuchos::RCP<Teuchos::ParameterList>& params);
00360 
00379 template<class Scalar, class MV, class OP>
00380 Teuchos::RCP<SolverManager<Scalar, MV, OP> >
00381 makeSolverManagerFromEnum (const EBelosSolverType solverType,
00382                            const Teuchos::RCP<Teuchos::ParameterList>& params)
00383 {
00384   typedef SolverManager<Scalar, MV, OP> base_type;
00385 
00386   switch (solverType) {
00387   case SOLVER_TYPE_BLOCK_GMRES: {
00388     typedef BlockGmresSolMgr<Scalar, MV, OP> impl_type;
00389     return makeSolverManagerTmpl<base_type, impl_type> (params);
00390     break;
00391   } 
00392   case SOLVER_TYPE_PSEUDO_BLOCK_GMRES: {
00393     typedef PseudoBlockGmresSolMgr<Scalar, MV, OP> impl_type;
00394     return makeSolverManagerTmpl<base_type, impl_type> (params);
00395     break;
00396   }
00397   case SOLVER_TYPE_BLOCK_CG: {
00398     typedef BlockCGSolMgr<Scalar, MV, OP> impl_type;
00399     return makeSolverManagerTmpl<base_type, impl_type> (params);
00400     break;
00401   }
00402   case SOLVER_TYPE_PSEUDO_BLOCK_CG: {
00403     typedef PseudoBlockCGSolMgr<Scalar, MV, OP> impl_type;
00404     return makeSolverManagerTmpl<base_type, impl_type> (params);
00405     break;
00406   }
00407   case SOLVER_TYPE_GCRODR: {
00408     typedef GCRODRSolMgr<Scalar, MV, OP> impl_type;
00409     return makeSolverManagerTmpl<base_type, impl_type> (params);
00410     break;
00411   }
00412   case SOLVER_TYPE_RCG: {
00413     typedef RCGSolMgr<Scalar, MV, OP> impl_type;
00414     return makeSolverManagerTmpl<base_type, impl_type> (params);
00415     break;
00416   }
00417   case SOLVER_TYPE_MINRES: {
00418     typedef MinresSolMgr<Scalar, MV, OP> impl_type;
00419     return makeSolverManagerTmpl<base_type, impl_type> (params);
00420     break;
00421   }
00422   case SOLVER_TYPE_LSQR: {
00423     typedef LSQRSolMgr<Scalar, MV, OP> impl_type;
00424     return makeSolverManagerTmpl<base_type, impl_type> (params);
00425     break;
00426   }
00427   default:
00428     TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 
00429              "Invalid EBelosSolverType enum value " << solverType 
00430              << ".  Please report this bug to the Belos developers.");
00431     // Compiler guard.
00432     return Teuchos::null;
00433   }
00434 }
00435 
00436 template<class SolverManagerBaseType, class SolverManagerType>
00437 Teuchos::RCP<SolverManagerBaseType>
00438 makeSolverManagerTmpl (const Teuchos::RCP<Teuchos::ParameterList>& params)
00439 {
00440   using Teuchos::ParameterList;
00441   using Teuchos::parameterList;
00442   using Teuchos::RCP;
00443 
00444   RCP<SolverManagerType> solver = rcp (new SolverManagerType);
00445 
00446   // Some solvers may not like to get a null ParameterList.  If params
00447   // is null, replace it with the solver's default parameters.
00448   RCP<ParameterList> pl;
00449   if (params.is_null()) {
00450     pl = parameterList (*solver->getValidParameters());
00451   } else {
00452     pl = params;
00453   }
00454   TEUCHOS_TEST_FOR_EXCEPTION(pl.is_null(), std::logic_error, 
00455            "ParameterList to pass to solver is null.  This "
00456            "should never happen.  Please report this bug to "
00457            "the Belos developers.");
00458   solver->setParameters (pl);
00459   return solver;
00460 }
00461 
00462 } // namespace details
00463 
00464 
00465 template<class Scalar, class MV, class OP>
00466 SolverFactory<Scalar, MV, OP>::SolverFactory()
00467 {
00468   aliasToCanonicalName_["GMRES"] = "Pseudoblock GMRES";
00469   // NOTE (mfh 29 Nov 2011) Accessing the flexible capability requires
00470   // setting a parameter in the solver's parameter list.  This affects
00471   // the SolverFactory's interface, since using the "Flexible GMRES"
00472   // alias requires modifying the user's parameter list if necessary.
00473   // This is a good idea because users may not know about the
00474   // parameter, or may have forgotten.
00475   aliasToCanonicalName_["Flexible GMRES"] = "Block GMRES";
00476   aliasToCanonicalName_["CG"] = "Pseudoblock CG";
00477   aliasToCanonicalName_["Recycling CG"] = "RCG";
00478   aliasToCanonicalName_["Recycling GMRES"] = "GCRODR";
00479   // For compatibility with Stratimikos' Belos adapter.
00480   aliasToCanonicalName_["Pseudo Block GMRES"] = "Pseudoblock GMRES";  
00481   aliasToCanonicalName_["Pseudo Block CG"] = "Pseudoblock CG";
00482 
00483   // Mapping from canonical solver name (a string) to its
00484   // corresponding enum value.  This mapping is one-to-one.
00485   canonicalNameToEnum_["Block GMRES"] = details::SOLVER_TYPE_BLOCK_GMRES;
00486   canonicalNameToEnum_["Pseudoblock GMRES"] = details::SOLVER_TYPE_PSEUDO_BLOCK_GMRES;
00487   canonicalNameToEnum_["Block CG"] = details::SOLVER_TYPE_BLOCK_CG;
00488   canonicalNameToEnum_["Pseudoblock CG"] = details::SOLVER_TYPE_PSEUDO_BLOCK_CG;
00489   canonicalNameToEnum_["GCRODR"] = details::SOLVER_TYPE_GCRODR;
00490   canonicalNameToEnum_["RCG"] = details::SOLVER_TYPE_RCG;
00491   canonicalNameToEnum_["MINRES"] = details::SOLVER_TYPE_MINRES;
00492   canonicalNameToEnum_["LSQR"] = details::SOLVER_TYPE_LSQR;
00493 }
00494 
00495 
00496 template<class Scalar, class MV, class OP>
00497 void
00498 SolverFactory<Scalar, MV, OP>::
00499 reviseParameterListForAlias (const std::string& aliasName,
00500            const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
00501 {
00502   TEUCHOS_TEST_FOR_EXCEPTION(solverParams.is_null(), std::logic_error,
00503     "Belos::SolverFactory::reviseParameterListForAlias: the input "
00504     "ParameterList is supposed to be nonnull.  Please report this "
00505     "bug to the Belos developers.");
00506   if (aliasName == "Flexible GMRES") {
00507     // "Gmres" uses title case in this solver's parameter list.  For
00508     // our alias, we prefer the all-capitals "GMRES" that the
00509     // algorithm's authors (Saad and Schultz) used.
00510     solverParams->set ("Flexible Gmres", true);
00511   }
00512 }
00513 
00514 
00515 template<class Scalar, class MV, class OP>
00516 Teuchos::RCP<typename SolverFactory<Scalar, MV, OP>::solver_base_type>
00517 SolverFactory<Scalar, MV, OP>::
00518 create (const std::string& solverName, 
00519   const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
00520 {
00521   // Check whether the given name is an alias.
00522   std::map<std::string, std::string>::const_iterator aliasIter = 
00523     aliasToCanonicalName_.find (solverName);
00524   const bool isAnAlias = (aliasIter != aliasToCanonicalName_.end());
00525   const std::string candidateCanonicalName = 
00526     isAnAlias ? aliasIter->second : solverName;
00527 
00528   // Get the canonical name.
00529   std::map<std::string, details::EBelosSolverType>::const_iterator canonicalIter =
00530     canonicalNameToEnum_.find (candidateCanonicalName);
00531   const bool validCanonicalName = (canonicalIter != canonicalNameToEnum_.end());
00532 
00533   // Check whether we found a canonical name.  If we didn't and the
00534   // input name is a valid alias, that's a bug.  Otherwise, the input
00535   // name is invalid.
00536   TEUCHOS_TEST_FOR_EXCEPTION(! validCanonicalName && isAnAlias, std::logic_error,
00537     "Valid alias \"" << solverName << "\" has candidate canonical name \"" 
00538     << candidateCanonicalName << "\", which is not a canonical solver name.  "
00539     "Please report this bug to the Belos developers.");
00540   TEUCHOS_TEST_FOR_EXCEPTION(! validCanonicalName && ! isAnAlias, 
00541     std::invalid_argument, "Invalid solver name \"" << solverName << "\".");
00542 
00543   // If the input list is null, we create a new list and use that.
00544   // This is OK because the effect of a null parameter list input is
00545   // to use default parameter values.  Thus, we can always replace a
00546   // null list with an empty list.
00547   Teuchos::RCP<Teuchos::ParameterList> pl = 
00548     solverParams.is_null() ? Teuchos::parameterList() : solverParams;
00549 
00550   // Possibly modify the input parameter list as needed.
00551   if (isAnAlias) {
00552     reviseParameterListForAlias (solverName, pl);
00553   }
00554 
00555   return details::makeSolverManagerFromEnum<Scalar, MV, OP> (canonicalIter->second, pl);
00556 }
00557 
00558 
00559 template<class Scalar, class MV, class OP>
00560 std::string
00561 SolverFactory<Scalar, MV, OP>::description() const
00562 {
00563   using Teuchos::TypeNameTraits;
00564   std::ostringstream os;
00565   os << "Belos::SolverFactory<" << TypeNameTraits<Scalar>::name()
00566      << ", " << TypeNameTraits<Scalar>::name()
00567      << ", " << TypeNameTraits<MV>::name()
00568      << ", " << TypeNameTraits<OP>::name()
00569      << ">";
00570   return os.str();
00571 }
00572 
00573 template<class Scalar, class MV, class OP>
00574 void
00575 SolverFactory<Scalar, MV, OP>::
00576 describe (Teuchos::FancyOStream& out, 
00577     const Teuchos::EVerbosityLevel verbLevel) const
00578 {
00579   using std::endl;
00580   typedef Teuchos::Array<std::string>::const_iterator iter_type;
00581 
00582   Teuchos::OSTab tab1 (out);
00583   out << this->description();
00584 
00585   // At higher verbosity levels, print out the list of supported solvers.
00586   if (static_cast<int> (verbLevel) > static_cast<int> (Teuchos::VERB_LOW)) {
00587     out << ":" << endl;
00588     Teuchos::OSTab tab2 (out);
00589     out << "Number of supported solvers: " << numSupportedSolvers() 
00590   << endl;
00591     out << "Supported canonical solver names:";
00592     {
00593       Teuchos::Array<std::string> names = canonicalSolverNames();
00594       for (iter_type iter = names.begin(); iter != names.end(); ++iter) {
00595   out << *iter;
00596   if (iter + 1 != names.end()) {
00597     out << ", ";
00598   }
00599       }
00600     }
00601     out << "Supported aliases to canonical names:";
00602     {
00603       Teuchos::Array<std::string> names = solverNameAliases();
00604       for (iter_type iter = names.begin(); iter != names.end(); ++iter) {
00605   out << *iter;
00606   if (iter + 1 != names.end()) {
00607     out << ", ";
00608   }
00609       }
00610     }
00611   }
00612 }
00613 
00614 template<class Scalar, class MV, class OP>
00615 int
00616 SolverFactory<Scalar, MV, OP>::numSupportedSolvers () const
00617 {
00618   return static_cast<int> (canonicalNameToEnum_.size());
00619 }
00620 
00621 template<class Scalar, class MV, class OP>
00622 Teuchos::Array<std::string>
00623 SolverFactory<Scalar, MV, OP>::canonicalSolverNames () const
00624 {
00625   Teuchos::Array<std::string> canonicalNames;
00626   typedef std::map<std::string, details::EBelosSolverType>::const_iterator iter_type;
00627   for (iter_type iter = canonicalNameToEnum_.begin(); 
00628        iter != canonicalNameToEnum_.end(); ++iter) {
00629     canonicalNames.push_back (iter->first);
00630   }
00631   return canonicalNames;
00632 }
00633 
00634 template<class Scalar, class MV, class OP>
00635 Teuchos::Array<std::string>
00636 SolverFactory<Scalar, MV, OP>::solverNameAliases () const
00637 {
00638   Teuchos::Array<std::string> names;
00639   {
00640     typedef std::map<std::string, std::string>::const_iterator iter_type;
00641     for (iter_type iter = aliasToCanonicalName_.begin(); 
00642    iter != aliasToCanonicalName_.end(); ++iter) {
00643       names.push_back (iter->first);
00644     }
00645   }
00646   return names;
00647 }
00648 
00649 template<class Scalar, class MV, class OP>
00650 Teuchos::Array<std::string>
00651 SolverFactory<Scalar, MV, OP>::supportedSolverNames () const
00652 {
00653   Teuchos::Array<std::string> names;
00654   {
00655     typedef std::map<std::string, std::string>::const_iterator iter_type;
00656     for (iter_type iter = aliasToCanonicalName_.begin(); 
00657    iter != aliasToCanonicalName_.end(); ++iter) {
00658       names.push_back (iter->first);
00659     }
00660   }
00661   {
00662     typedef std::map<std::string, details::EBelosSolverType>::const_iterator iter_type;
00663     for (iter_type iter = canonicalNameToEnum_.begin(); 
00664    iter != canonicalNameToEnum_.end(); ++iter) {
00665       names.push_back (iter->first);
00666     }
00667   }
00668   return names;
00669 }
00670 
00671 } // namespace Belos
00672 
00673 #endif // __Belos_SolverFactory_hpp
00674 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines