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