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 <BelosBlockCGSolMgr.hpp>
00050 #include <BelosBlockGmresSolMgr.hpp>
00051 #include <BelosGCRODRSolMgr.hpp>
00052 #include <BelosPseudoBlockCGSolMgr.hpp>
00053 #include <BelosPseudoBlockGmresSolMgr.hpp>
00054 #include <BelosPseudoBlockStochasticCGSolMgr.hpp>
00055 #include <BelosLSQRSolMgr.hpp>
00056 #include <BelosMinresSolMgr.hpp>
00057 #include <BelosGmresPolySolMgr.hpp>
00058 #include <BelosPCPGSolMgr.hpp>
00059 #include <BelosRCGSolMgr.hpp>
00060 #include <BelosTFQMRSolMgr.hpp>
00061 
00062 #include <Teuchos_Array.hpp>
00063 #include <Teuchos_Describable.hpp>
00064 #include <Teuchos_StandardCatchMacros.hpp>
00065 #include <Teuchos_TypeNameTraits.hpp>
00066 
00067 #include <algorithm>
00068 #include <map>
00069 #include <sstream>
00070 #include <stdexcept>
00071 #include <vector>
00072 
00073 namespace Belos {
00074 
00075 namespace details {
00076 
00095 enum EBelosSolverType {
00096   SOLVER_TYPE_BLOCK_GMRES,
00097   SOLVER_TYPE_PSEUDO_BLOCK_GMRES,
00098   SOLVER_TYPE_BLOCK_CG,
00099   SOLVER_TYPE_PSEUDO_BLOCK_CG,
00100   SOLVER_TYPE_GCRODR,
00101   SOLVER_TYPE_RCG,
00102   SOLVER_TYPE_MINRES,
00103   SOLVER_TYPE_LSQR,
00104   SOLVER_TYPE_STOCHASTIC_CG,
00105   SOLVER_TYPE_TFQMR,
00106   SOLVER_TYPE_GMRES_POLY,
00107   SOLVER_TYPE_PCPG
00108 };
00109 
00110 } // namespace details
00111 
00219 template<class Scalar, class MV, class OP>
00220 class SolverFactory : public Teuchos::Describable {
00221 public:
00228   typedef SolverManager<Scalar, MV, OP> solver_base_type;
00229 
00231   SolverFactory();
00232 
00262   Teuchos::RCP<solver_base_type>
00263   create (const std::string& solverName,
00264           const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
00265 
00271   int numSupportedSolvers () const;
00272 
00278   Teuchos::Array<std::string> supportedSolverNames () const;
00279 
00281   bool isSupported (const std::string& solverName) const;
00282 
00284 
00285 
00287   std::string description() const;
00288 
00294   void describe (Teuchos::FancyOStream& out,
00295                  const Teuchos::EVerbosityLevel verbLevel = Teuchos::Describable::verbLevel_default) const;
00297 
00298 private:
00311   std::map<std::string, std::string> aliasToCanonicalName_;
00312 
00326   std::map<std::string, details::EBelosSolverType> canonicalNameToEnum_;
00327 
00333   void
00334   reviseParameterListForAlias (const std::string& aliasName,
00335                                const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
00336 
00338   Teuchos::Array<std::string> canonicalSolverNames () const;
00339 
00341   Teuchos::Array<std::string> solverNameAliases () const;
00342 };
00343 
00344 
00345 namespace { // anonymous
00346 
00348 void
00349 printStringArray (std::ostream& out,
00350                   const Teuchos::ArrayView<const std::string>& array)
00351 {
00352   typedef Teuchos::ArrayView<std::string>::const_iterator iter_type;
00353 
00354   out << "[";
00355   for (iter_type iter = array.begin(); iter != array.end(); ++iter) {
00356     out << "\"" << *iter << "\"";
00357     if (iter + 1 != array.end()) {
00358       out << ", ";
00359     }
00360   }
00361   out << "]";
00362 }
00363 
00364 } // namespace (anonymous)
00365 
00366 
00367 namespace details {
00368 
00387 template<class SolverManagerBaseType, class SolverManagerType>
00388 Teuchos::RCP<SolverManagerBaseType>
00389 makeSolverManagerTmpl (const Teuchos::RCP<Teuchos::ParameterList>& params);
00390 
00409 template<class Scalar, class MV, class OP>
00410 Teuchos::RCP<SolverManager<Scalar, MV, OP> >
00411 makeSolverManagerFromEnum (const EBelosSolverType solverType,
00412                            const Teuchos::RCP<Teuchos::ParameterList>& params)
00413 {
00414   typedef SolverManager<Scalar, MV, OP> base_type;
00415 
00416   switch (solverType) {
00417   case SOLVER_TYPE_BLOCK_GMRES: {
00418     typedef BlockGmresSolMgr<Scalar, MV, OP> impl_type;
00419     return makeSolverManagerTmpl<base_type, impl_type> (params);
00420     break;
00421   }
00422   case SOLVER_TYPE_PSEUDO_BLOCK_GMRES: {
00423     typedef PseudoBlockGmresSolMgr<Scalar, MV, OP> impl_type;
00424     return makeSolverManagerTmpl<base_type, impl_type> (params);
00425     break;
00426   }
00427   case SOLVER_TYPE_BLOCK_CG: {
00428     typedef BlockCGSolMgr<Scalar, MV, OP> impl_type;
00429     return makeSolverManagerTmpl<base_type, impl_type> (params);
00430     break;
00431   }
00432   case SOLVER_TYPE_PSEUDO_BLOCK_CG: {
00433     typedef PseudoBlockCGSolMgr<Scalar, MV, OP> impl_type;
00434     return makeSolverManagerTmpl<base_type, impl_type> (params);
00435     break;
00436   }
00437   case SOLVER_TYPE_GCRODR: {
00438     typedef GCRODRSolMgr<Scalar, MV, OP> impl_type;
00439     return makeSolverManagerTmpl<base_type, impl_type> (params);
00440     break;
00441   }
00442   case SOLVER_TYPE_RCG: {
00443     typedef RCGSolMgr<Scalar, MV, OP> impl_type;
00444     return makeSolverManagerTmpl<base_type, impl_type> (params);
00445     break;
00446   }
00447   case SOLVER_TYPE_MINRES: {
00448     typedef MinresSolMgr<Scalar, MV, OP> impl_type;
00449     return makeSolverManagerTmpl<base_type, impl_type> (params);
00450     break;
00451   }
00452   case SOLVER_TYPE_LSQR: {
00453     typedef LSQRSolMgr<Scalar, MV, OP> impl_type;
00454     return makeSolverManagerTmpl<base_type, impl_type> (params);
00455     break;
00456   }
00457   case SOLVER_TYPE_STOCHASTIC_CG: {
00458     typedef PseudoBlockStochasticCGSolMgr<Scalar, MV, OP> impl_type;
00459     return makeSolverManagerTmpl<base_type, impl_type> (params);
00460   }
00461   case SOLVER_TYPE_TFQMR: {
00462     typedef TFQMRSolMgr<Scalar, MV, OP> impl_type;
00463     return makeSolverManagerTmpl<base_type, impl_type> (params);
00464   }
00465   case SOLVER_TYPE_GMRES_POLY: {
00466     typedef GmresPolySolMgr<Scalar, MV, OP> impl_type;
00467     return makeSolverManagerTmpl<base_type, impl_type> (params);
00468   }
00469   case SOLVER_TYPE_PCPG: {
00470     typedef PCPGSolMgr<Scalar, MV, OP> impl_type;
00471     return makeSolverManagerTmpl<base_type, impl_type> (params);
00472   }
00473   default: // Fall through; let the code below handle it.
00474     TEUCHOS_TEST_FOR_EXCEPTION(
00475       true, std::logic_error, "Belos::SolverFactory: Invalid EBelosSolverType "
00476       "enum value " << solverType << ".  Please report this bug to the Belos "
00477       "developers.");
00478   }
00479 
00480   // Compiler guard.  This may result in a warning on some compilers
00481   // for an unreachable statement, but it will prevent a warning on
00482   // other compilers for a "missing return statement at end of
00483   // non-void function."
00484   return Teuchos::null;
00485 }
00486 
00487 template<class SolverManagerBaseType, class SolverManagerType>
00488 Teuchos::RCP<SolverManagerBaseType>
00489 makeSolverManagerTmpl (const Teuchos::RCP<Teuchos::ParameterList>& params)
00490 {
00491   using Teuchos::ParameterList;
00492   using Teuchos::parameterList;
00493   using Teuchos::RCP;
00494 
00495   RCP<SolverManagerType> solver = rcp (new SolverManagerType);
00496 
00497   // Some solvers may not like to get a null ParameterList.  If params
00498   // is null, replace it with the solver's default parameters.
00499   RCP<ParameterList> pl;
00500   if (params.is_null()) {
00501     pl = parameterList (*solver->getValidParameters ());
00502   } else {
00503     pl = params;
00504   }
00505   TEUCHOS_TEST_FOR_EXCEPTION(
00506     pl.is_null(), std::logic_error,
00507     "Belos::SolverFactory: ParameterList to pass to solver is null.  This "
00508     "should never happen.  Please report this bug to the Belos developers.");
00509   solver->setParameters (pl);
00510   return solver;
00511 }
00512 
00513 } // namespace details
00514 
00515 
00516 template<class Scalar, class MV, class OP>
00517 SolverFactory<Scalar, MV, OP>::SolverFactory()
00518 {
00519   aliasToCanonicalName_["GMRES"] = "Pseudoblock GMRES";
00520   // NOTE (mfh 29 Nov 2011) Accessing the flexible capability requires
00521   // setting a parameter in the solver's parameter list.  This affects
00522   // the SolverFactory's interface, since using the "Flexible GMRES"
00523   // alias requires modifying the user's parameter list if necessary.
00524   // This is a good idea because users may not know about the
00525   // parameter, or may have forgotten.
00526   aliasToCanonicalName_["Block GMRES"] = "Block GMRES";
00527   aliasToCanonicalName_["Flexible GMRES"] = "Block GMRES";
00528   aliasToCanonicalName_["CG"] = "Pseudoblock CG";
00529   aliasToCanonicalName_["PseudoBlockCG"] = "Pseudoblock CG";
00530   aliasToCanonicalName_["Stochastic CG"] = "Pseudoblock Stochastic CG";
00531   aliasToCanonicalName_["Recycling CG"] = "RCG";
00532   aliasToCanonicalName_["Recycling GMRES"] = "GCRODR";
00533   // For compatibility with Stratimikos' Belos adapter.
00534   aliasToCanonicalName_["Pseudo Block GMRES"] = "Pseudoblock GMRES";
00535   aliasToCanonicalName_["PseudoBlockGmres"] = "Pseudoblock GMRES";
00536   aliasToCanonicalName_["Pseudo Block CG"] = "Pseudoblock CG";
00537   aliasToCanonicalName_["PseudoBlockCG"] = "Pseudoblock CG";
00538   aliasToCanonicalName_["Transpose-Free QMR"] = "TFQMR";
00539   aliasToCanonicalName_["GmresPoly"] = "Hybrid Block GMRES";
00540   aliasToCanonicalName_["Seed GMRES"] = "Hybrid Block GMRES";
00541   aliasToCanonicalName_["CGPoly"] = "PCPG";
00542   aliasToCanonicalName_["Seed CG"] = "PCPG";
00543 
00544   // Mapping from canonical solver name (a string) to its
00545   // corresponding enum value.  This mapping is one-to-one.
00546   canonicalNameToEnum_["Block GMRES"] = details::SOLVER_TYPE_BLOCK_GMRES;
00547   canonicalNameToEnum_["Pseudoblock GMRES"] = details::SOLVER_TYPE_PSEUDO_BLOCK_GMRES;
00548   canonicalNameToEnum_["Block CG"] = details::SOLVER_TYPE_BLOCK_CG;
00549   canonicalNameToEnum_["Pseudoblock CG"] = details::SOLVER_TYPE_PSEUDO_BLOCK_CG;
00550   canonicalNameToEnum_["Pseudoblock Stochastic CG"] = details::SOLVER_TYPE_STOCHASTIC_CG;
00551   canonicalNameToEnum_["GCRODR"] = details::SOLVER_TYPE_GCRODR;
00552   canonicalNameToEnum_["RCG"] = details::SOLVER_TYPE_RCG;
00553   canonicalNameToEnum_["MINRES"] = details::SOLVER_TYPE_MINRES;
00554   canonicalNameToEnum_["LSQR"] = details::SOLVER_TYPE_LSQR;
00555   canonicalNameToEnum_["TFQMR"] = details::SOLVER_TYPE_TFQMR;
00556   canonicalNameToEnum_["Hybrid Block GMRES"] = details::SOLVER_TYPE_GMRES_POLY;
00557   canonicalNameToEnum_["PCPG"] = details::SOLVER_TYPE_PCPG;
00558 }
00559 
00560 
00561 template<class Scalar, class MV, class OP>
00562 void
00563 SolverFactory<Scalar, MV, OP>::
00564 reviseParameterListForAlias (const std::string& aliasName,
00565                              const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
00566 {
00567   TEUCHOS_TEST_FOR_EXCEPTION(solverParams.is_null(), std::logic_error,
00568     "Belos::SolverFactory::reviseParameterListForAlias: the input "
00569     "ParameterList is supposed to be nonnull.  Please report this "
00570     "bug to the Belos developers.");
00571   if (aliasName == "Flexible GMRES") {
00572     // "Gmres" uses title case in this solver's parameter list.  For
00573     // our alias, we prefer the all-capitals "GMRES" that the
00574     // algorithm's authors (Saad and Schultz) used.
00575     solverParams->set ("Flexible Gmres", true);
00576   }
00577 }
00578 
00579 
00580 template<class Scalar, class MV, class OP>
00581 Teuchos::RCP<typename SolverFactory<Scalar, MV, OP>::solver_base_type>
00582 SolverFactory<Scalar, MV, OP>::
00583 create (const std::string& solverName,
00584         const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
00585 {
00586   // Check whether the given name is an alias.
00587   std::map<std::string, std::string>::const_iterator aliasIter =
00588     aliasToCanonicalName_.find (solverName);
00589   const bool isAnAlias = (aliasIter != aliasToCanonicalName_.end());
00590   const std::string candidateCanonicalName =
00591     isAnAlias ? aliasIter->second : solverName;
00592 
00593   // Get the canonical name.
00594   std::map<std::string, details::EBelosSolverType>::const_iterator canonicalIter =
00595     canonicalNameToEnum_.find (candidateCanonicalName);
00596   const bool validCanonicalName = (canonicalIter != canonicalNameToEnum_.end());
00597 
00598   // Check whether we found a canonical name.  If we didn't and the
00599   // input name is a valid alias, that's a bug.  Otherwise, the input
00600   // name is invalid.
00601   TEUCHOS_TEST_FOR_EXCEPTION(! validCanonicalName && isAnAlias, std::logic_error,
00602     "Valid alias \"" << solverName << "\" has candidate canonical name \""
00603     << candidateCanonicalName << "\", which is not a canonical solver name.  "
00604     "Please report this bug to the Belos developers.");
00605   TEUCHOS_TEST_FOR_EXCEPTION(! validCanonicalName && ! isAnAlias,
00606     std::invalid_argument, "Invalid solver name \"" << solverName << "\".");
00607 
00608   // If the input list is null, we create a new list and use that.
00609   // This is OK because the effect of a null parameter list input is
00610   // to use default parameter values.  Thus, we can always replace a
00611   // null list with an empty list.
00612   Teuchos::RCP<Teuchos::ParameterList> pl =
00613     solverParams.is_null() ? Teuchos::parameterList() : solverParams;
00614 
00615   // Possibly modify the input parameter list as needed.
00616   if (isAnAlias) {
00617     reviseParameterListForAlias (solverName, pl);
00618   }
00619 
00620   return details::makeSolverManagerFromEnum<Scalar, MV, OP> (canonicalIter->second, pl);
00621 }
00622 
00623 
00624 template<class Scalar, class MV, class OP>
00625 std::string
00626 SolverFactory<Scalar, MV, OP>::description() const
00627 {
00628   using Teuchos::TypeNameTraits;
00629 
00630   std::ostringstream out;
00631   out << "\"Belos::SolverFactory\": {";
00632   if (this->getObjectLabel () != "") {
00633     out << "Label: " << this->getObjectLabel () << ", ";
00634   }
00635   out << "Scalar: " << TypeNameTraits<Scalar>::name ()
00636       << ", MV: " << TypeNameTraits<MV>::name ()
00637       << ", OP: " << TypeNameTraits<OP>::name ()
00638       << "}";
00639   return out.str ();
00640 }
00641 
00642 
00643 template<class Scalar, class MV, class OP>
00644 void
00645 SolverFactory<Scalar, MV, OP>::
00646 describe (Teuchos::FancyOStream& out,
00647           const Teuchos::EVerbosityLevel verbLevel) const
00648 {
00649   using Teuchos::TypeNameTraits;
00650   using std::endl;
00651 
00652   const Teuchos::EVerbosityLevel vl =
00653     (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
00654 
00655   if (vl == Teuchos::VERB_NONE) {
00656     return;
00657   }
00658 
00659   // By convention, describe() always begins with a tab.
00660   Teuchos::OSTab tab0 (out);
00661   // The description prints in YAML format.  The class name needs to
00662   // be protected with quotes, so that YAML doesn't get confused
00663   // between the colons in the class name and the colon separating
00664   // (key,value) pairs.
00665   out << "\"Belos::SolverFactory\":" << endl;
00666   if (this->getObjectLabel () != "") {
00667     out << "Label: " << this->getObjectLabel () << endl;
00668   }
00669   {
00670     out << "Template parameters:" << endl;
00671     Teuchos::OSTab tab1 (out);
00672     out << "Scalar: " << TypeNameTraits<Scalar>::name () << endl
00673         << "MV: " << TypeNameTraits<MV>::name () << endl
00674         << "OP: " << TypeNameTraits<OP>::name () << endl;
00675   }
00676 
00677   // At higher verbosity levels, print out the list of supported solvers.
00678   if (vl > Teuchos::VERB_LOW) {
00679     Teuchos::OSTab tab1 (out);
00680     out << "Number of solvers: " << numSupportedSolvers ()
00681         << endl;
00682     out << "Canonical solver names: ";
00683     printStringArray (out, canonicalSolverNames ());
00684     out << endl;
00685 
00686     out << "Aliases to canonical names: ";
00687     printStringArray (out, solverNameAliases ());
00688     out << endl;
00689   }
00690 }
00691 
00692 template<class Scalar, class MV, class OP>
00693 int
00694 SolverFactory<Scalar, MV, OP>::numSupportedSolvers () const
00695 {
00696   return static_cast<int> (canonicalNameToEnum_.size());
00697 }
00698 
00699 template<class Scalar, class MV, class OP>
00700 Teuchos::Array<std::string>
00701 SolverFactory<Scalar, MV, OP>::canonicalSolverNames () const
00702 {
00703   Teuchos::Array<std::string> canonicalNames;
00704   typedef std::map<std::string, details::EBelosSolverType>::const_iterator iter_type;
00705   for (iter_type iter = canonicalNameToEnum_.begin();
00706        iter != canonicalNameToEnum_.end(); ++iter) {
00707     canonicalNames.push_back (iter->first);
00708   }
00709   return canonicalNames;
00710 }
00711 
00712 template<class Scalar, class MV, class OP>
00713 Teuchos::Array<std::string>
00714 SolverFactory<Scalar, MV, OP>::solverNameAliases () const
00715 {
00716   Teuchos::Array<std::string> names;
00717   {
00718     typedef std::map<std::string, std::string>::const_iterator iter_type;
00719     for (iter_type iter = aliasToCanonicalName_.begin();
00720          iter != aliasToCanonicalName_.end(); ++iter) {
00721       names.push_back (iter->first);
00722     }
00723   }
00724   return names;
00725 }
00726 
00727 template<class Scalar, class MV, class OP>
00728 Teuchos::Array<std::string>
00729 SolverFactory<Scalar, MV, OP>::supportedSolverNames () const
00730 {
00731   Teuchos::Array<std::string> names;
00732   {
00733     typedef std::map<std::string, std::string>::const_iterator iter_type;
00734     for (iter_type iter = aliasToCanonicalName_.begin();
00735          iter != aliasToCanonicalName_.end(); ++iter) {
00736       names.push_back (iter->first);
00737     }
00738   }
00739   {
00740     typedef std::map<std::string, details::EBelosSolverType>::const_iterator iter_type;
00741     for (iter_type iter = canonicalNameToEnum_.begin();
00742          iter != canonicalNameToEnum_.end(); ++iter) {
00743       names.push_back (iter->first);
00744     }
00745   }
00746   return names;
00747 }
00748 
00749 } // namespace Belos
00750 
00751 #endif // __Belos_SolverFactory_hpp
00752 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines