Stratimikos Version of the Day
Stratimikos_DefaultLinearSolverBuilder.cpp
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 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 //#define THYRA_DEFAULT_REAL_LINEAR_SOLVER_BUILDER_DUMP
00030 
00031 #include "Stratimikos_InternalConfig.h"
00032 #include "Stratimikos_DefaultLinearSolverBuilder.hpp"
00033 #include "Thyra_DelayedLinearOpWithSolveFactory.hpp"
00034 #include "Teuchos_AbstractFactoryStd.hpp"
00035 #include "Teuchos_CommandLineProcessor.hpp"
00036 #include "Teuchos_XMLParameterListHelpers.hpp"
00037 #include "Teuchos_GlobalMPISession.hpp"
00038 
00039 #ifdef HAVE_STRATIMIKOS_AMESOS
00040 #  include "Thyra_AmesosLinearOpWithSolveFactory.hpp"
00041 #endif
00042 #ifdef HAVE_STRATIMIKOS_AZTECOO
00043 #  include "Thyra_AztecOOLinearOpWithSolveFactory.hpp"
00044 #endif
00045 #ifdef HAVE_STRATIMIKOS_BELOS
00046 #  include "Thyra_BelosLinearOpWithSolveFactory.hpp"
00047 #endif
00048 #ifdef HAVE_STRATIMIKOS_IFPACK
00049 #  include "Thyra_IfpackPreconditionerFactory.hpp"
00050 #endif
00051 #ifdef HAVE_STRATIMIKOS_ML
00052 #  include "Thyra_MLPreconditionerFactory.hpp"
00053 #endif
00054 
00055 
00056 namespace {
00057 
00058 
00059 const std::string LinearSolverType_name    = "Linear Solver Type";
00060 const std::string LinearSolverTypes_name   = "Linear Solver Types";
00061 const std::string PreconditionerType_name    = "Preconditioner Type";
00062 const std::string PreconditionerTypes_name   = "Preconditioner Types";
00063 const std::string None_name = "None";
00064 const std::string EnableDelayedSolverConstruction_name = "Enable Delayed Solver Construction";
00065 const bool EnableDelayedSolverConstruction_default = false;
00066 
00067 
00068 } // namespace 
00069 
00070 
00071 namespace Stratimikos {
00072 
00073 
00074 // Constructors/Initializers/Accessors
00075 
00076 
00077 DefaultLinearSolverBuilder::DefaultLinearSolverBuilder(
00078   const std::string    &paramsXmlFileName_in
00079   ,const std::string   &extraParamsXmlString_in
00080   ,const std::string   &paramsUsedXmlOutFileName_in
00081   ,const std::string   &paramsXmlFileNameOption_in
00082   ,const std::string   &extraParamsXmlStringOption_in
00083   ,const std::string   &paramsUsedXmlOutFileNameOption_in
00084   )
00085   :paramsXmlFileName_(paramsXmlFileName_in)
00086   ,extraParamsXmlString_(extraParamsXmlString_in)
00087   ,paramsUsedXmlOutFileName_(paramsUsedXmlOutFileName_in)
00088   ,paramsXmlFileNameOption_(paramsXmlFileNameOption_in)
00089   ,extraParamsXmlStringOption_(extraParamsXmlStringOption_in)
00090   ,paramsUsedXmlOutFileNameOption_(paramsUsedXmlOutFileNameOption_in)
00091   ,enableDelayedSolverConstruction_(EnableDelayedSolverConstruction_default)
00092 {
00093   this->initializeDefaults();
00094 }
00095 
00096 
00097 DefaultLinearSolverBuilder::~DefaultLinearSolverBuilder()
00098 {
00099 #ifdef TEUCHOS_DEBUG
00100   // Validate that we read the parameters correctly!
00101   if (nonnull(paramList_)) {
00102     paramList_->validateParameters(*this->getValidParameters());
00103   }
00104 #endif    
00105 }
00106 
00107 
00108 void DefaultLinearSolverBuilder::setLinearSolveStrategyFactory(
00109   const RCP<const AbstractFactory<Thyra::LinearOpWithSolveFactoryBase<double> > >
00110   &solveStrategyFactory,
00111   const std::string &solveStrategyName,
00112   const bool makeDefault
00113   )
00114 {
00115   validLowsfNames_.push_back(solveStrategyName);
00116   lowsfArray_.push_back(solveStrategyFactory);
00117   validParamList_ = Teuchos::null;
00118   if (makeDefault) {
00119     setDefaultLinearSolveStrategyFactoryName(solveStrategyName);
00120   }
00121 }
00122 
00123 
00124 void DefaultLinearSolverBuilder::setDefaultLinearSolveStrategyFactoryName(
00125   const std::string &solveStrategyName)
00126 {
00127   defaultLOWSF_ = solveStrategyName;
00128 }
00129 
00130 
00131 void DefaultLinearSolverBuilder::setPreconditioningStrategyFactory(
00132   const RCP<const AbstractFactory<Thyra::PreconditionerFactoryBase<double> > >
00133   &precStrategyFactory,
00134   const std::string &precStrategyName,
00135   const bool makeDefault
00136   )
00137 {
00138   validPfNames_.push_back(precStrategyName);
00139   pfArray_.push_back(precStrategyFactory);
00140   validParamList_ = Teuchos::null;
00141   if (makeDefault) {
00142     setDefaultPreconditioningStrategyFactoryName(precStrategyName);
00143   }
00144 }
00145 
00146 
00147 void DefaultLinearSolverBuilder::setDefaultPreconditioningStrategyFactoryName(
00148   const std::string &precStrategyName)
00149 {
00150   defaultPF_ = precStrategyName;
00151 }
00152 
00153 
00154 void DefaultLinearSolverBuilder::setupCLP( Teuchos::CommandLineProcessor *clp )
00155 {
00156   TEUCHOS_TEST_FOR_EXCEPT(clp==NULL);
00157   clp->setOption(
00158     paramsXmlFileNameOption().c_str(),&paramsXmlFileName_
00159     ,"Name of an XML file containing parameters for linear solver "
00160     "options to be appended first."
00161     );
00162   clp->setOption(
00163     extraParamsXmlStringOption().c_str(),&extraParamsXmlString_
00164     ,"An XML string containing linear solver parameters to be appended second."
00165     );
00166   clp->setOption(
00167     paramsUsedXmlOutFileNameOption().c_str(),&paramsUsedXmlOutFileName_
00168     ,"Name of an XML file that can be written with the parameter list after it "
00169     "has been used on completion of this program."
00170     );
00171 }
00172 
00173 
00174 void DefaultLinearSolverBuilder::readParameters( std::ostream *out )
00175 {
00176   using Teuchos::parameterList;
00177   using Teuchos::ptr;
00178   using Teuchos::updateParametersFromXmlFile;
00179   using Teuchos::updateParametersFromXmlString;
00180   using std::endl;
00181   
00182   if (!paramList_.get()) {
00183     paramList_ = parameterList("DefaultLinearSolverBuilder");
00184   }
00185   if (paramsXmlFileName().length()) {
00186     if (out) {
00187       *out << endl << "Reading parameters from XML file \"" 
00188            << paramsXmlFileName() << "\" ..." << endl;
00189     }
00190     updateParametersFromXmlFile (paramsXmlFileName (), paramList_.ptr());
00191   }
00192   if (extraParamsXmlString().length()) {
00193     if (out) {
00194       *out << endl << "Appending extra parameters from the XML string \""
00195            << extraParamsXmlString() << "\" ..." << endl;
00196     }
00197     updateParametersFromXmlString (extraParamsXmlString (), paramList_.ptr());
00198   }
00199   setParameterList(paramList_);
00200 }
00201 
00202 
00203 void DefaultLinearSolverBuilder::writeParamsFile(
00204   const Thyra::LinearOpWithSolveFactoryBase<double> &lowsFactory,
00205   const std::string &outputXmlFileName
00206   ) const
00207 {
00208   justInTimeInitialize();
00209   const std::string xmlOutputFile =
00210     ( outputXmlFileName.length() ? outputXmlFileName : paramsUsedXmlOutFileName() );
00211   if (xmlOutputFile.length()) {
00212     Teuchos::writeParameterListToXmlFile(*paramList_, xmlOutputFile);
00213   }
00214 }
00215 
00216 
00217 std::string
00218 DefaultLinearSolverBuilder::getLinearSolveStrategyName() const
00219 {
00220   justInTimeInitialize();
00221   return lowsfValidator_->getStringValue(*paramList_, LinearSolverType_name,
00222     defaultLOWSF_);
00223 }
00224 
00225 
00226 std::string
00227 DefaultLinearSolverBuilder::getPreconditionerStrategyName() const
00228 {
00229   justInTimeInitialize();
00230   return pfValidator_->getStringValue(*paramList_, PreconditionerType_name,
00231     defaultPF_);
00232 }
00233 
00234 
00235 // Overridden from ParameterListAcceptor
00236 
00237 
00238 void DefaultLinearSolverBuilder::setParameterList(
00239   RCP<Teuchos::ParameterList> const& paramList
00240   )
00241 {
00242   TEUCHOS_TEST_FOR_EXCEPT(is_null(paramList));
00243   paramList->validateParameters(*this->getValidParameters());
00244   paramList_ = paramList;
00245   enableDelayedSolverConstruction_ = paramList_->get(
00246     EnableDelayedSolverConstruction_name, EnableDelayedSolverConstruction_default );
00247 }
00248 
00249 
00250 RCP<Teuchos::ParameterList>
00251 DefaultLinearSolverBuilder::getNonconstParameterList()
00252 {
00253   return paramList_;
00254 }
00255 
00256 
00257 RCP<Teuchos::ParameterList>
00258 DefaultLinearSolverBuilder::unsetParameterList()
00259 {
00260   RCP<Teuchos::ParameterList> _paramList = paramList_;
00261   paramList_ = Teuchos::null;
00262   return _paramList;
00263 }
00264 
00265 
00266 RCP<const Teuchos::ParameterList>
00267 DefaultLinearSolverBuilder::getParameterList() const
00268 {
00269   return paramList_;
00270 }
00271 
00272 
00273 RCP<const Teuchos::ParameterList>
00274 DefaultLinearSolverBuilder::getValidParameters() const
00275 {
00276   using Teuchos::rcp_implicit_cast;
00277   typedef Teuchos::ParameterEntryValidator PEV;
00278   if (is_null(validParamList_)) {
00279     RCP<Teuchos::ParameterList>
00280       validParamList = Teuchos::rcp(new Teuchos::ParameterList);
00281     // Linear Solver Types
00282     lowsfValidator_ = Teuchos::rcp(
00283       new Teuchos::StringToIntegralParameterEntryValidator<int>(
00284         validLowsfNames_,LinearSolverType_name
00285         )
00286       );
00287     validParamList->set(
00288       LinearSolverType_name, defaultLOWSF_,
00289       (std::string("Determines the type of linear solver that will be used.\n")
00290         + "The parameters for each solver type are specified in the sublist \""
00291         + LinearSolverTypes_name + "\"").c_str(),
00292       rcp_implicit_cast<const PEV>(lowsfValidator_)
00293       );
00294     Teuchos::ParameterList &linearSolverTypesSL = validParamList->sublist(
00295       LinearSolverTypes_name,false,
00296       "Sublists for each of the linear solver types set using the parameter\n"
00297       "\"" + LinearSolverType_name + "\".  Note that the options for each\n"
00298       "linear solver type given below will only be used if linear solvers\n"
00299       "of that type are created.  It is fine to list parameter sublists for\n"
00300       "linear solver types that are not used."
00301       );
00302     for( int i = 0; i < static_cast<int>(lowsfArray_.size()); ++i ) {
00303       const std::string
00304         &lsname = validLowsfNames_[i];
00305       const RCP<Thyra::LinearOpWithSolveFactoryBase<double> >
00306         lowsf = lowsfArray_[i]->create();
00307       linearSolverTypesSL.sublist(lsname).setParameters(*lowsf->getValidParameters()
00308         ).disableRecursiveValidation();
00309     }
00310     // Preconditioner Type
00311     pfValidator_ = Teuchos::rcp(
00312       new Teuchos::StringToIntegralParameterEntryValidator<int>(
00313         validPfNames_, PreconditionerType_name ) );
00314     validParamList->set(
00315       PreconditionerType_name, defaultPF_,
00316       (std::string("Determines the type of preconditioner that will be used.\n")
00317         + "This option is only meaningful for linear solvers that accept preconditioner"
00318         + " factory objects!\n"
00319         + "The parameters for each preconditioner are specified in the sublist \""
00320         + PreconditionerTypes_name + "\"").c_str(),
00321       rcp_implicit_cast<const PEV>(pfValidator_)
00322       );
00323     Teuchos::ParameterList &precTypesSL = validParamList->sublist(
00324         PreconditionerTypes_name,false,
00325         "Sublists for each of the preconditioner types set using the parameter\n"
00326         "\"" + PreconditionerType_name + "\".  Note that the options for each\n"
00327         "preconditioner type given below will only be used if preconditioners\n"
00328         "of that type are created.  It is fine to list parameter sublists for\n"
00329         "preconditioner types that are not used."
00330         );
00331     for( int i = 0; i < static_cast<int>(pfArray_.size()); ++i ) {
00332       const std::string
00333         &pfname = validPfNames_[i+1]; // "None" is the 0th entry!
00334       const RCP<Thyra::PreconditionerFactoryBase<double> >
00335         pf = pfArray_[i]->create();
00336       precTypesSL.sublist(pfname).setParameters(*pf->getValidParameters()
00337         ).disableRecursiveValidation();
00338     }
00339     // 
00340     validParamList->set(
00341       EnableDelayedSolverConstruction_name, EnableDelayedSolverConstruction_default,
00342       "When this option is set to true, the linear solver factory will be wrapped\n"
00343       "in a delayed evaluation Decorator factory object.  This results in a delay\n"
00344       "in the creation of a linear solver (and the associated preconditioner) until\n"
00345       "the first solve is actually performed.  This helps in cases where it is not\n"
00346       "known a-priori if a linear solve will be needed on a given linear operator and\n"
00347       "therefore can significantly improve performance for some types of algorithms\n"
00348       "such as NOX and LOCA."
00349       );
00350     //
00351     validParamList_ = validParamList;
00352   }
00353   return validParamList_;
00354 }
00355 
00356   
00357 // Overridden from LinearSolverBuilderBase.
00358 
00359 
00360 RCP<Thyra::LinearOpWithSolveFactoryBase<double> >
00361 DefaultLinearSolverBuilder::createLinearSolveStrategy(
00362   const std::string &linearSolveStrategyName
00363   ) const
00364 {
00365   justInTimeInitialize();
00366 
00367   // Get the name of the linear solve strategy
00368 #ifdef THYRA_DEFAULT_REAL_LINEAR_SOLVER_BUILDER_DUMP
00369   std::cout << "\nEntering DefaultLinearSolverBuilder"
00370             << "::createLinearSolveStrategy(...) ...\n";
00371   std::cout << "\nlinearSolveStrategyName = \""
00372             << linearSolveStrategyName << "\"\n";
00373   std::cout << "\nlinearSolveStrategyName.length() = "
00374             << linearSolveStrategyName.length() << "\n";
00375   std::cout << "\ndefaultLOWSF_ = \"" << defaultLOWSF_ << "\"\n";
00376   std::cout << "\nthis->getLinearSolveStrategyName() = \""
00377             << this->getLinearSolveStrategyName() << "\"\n";
00378 #endif
00379   const std::string
00380     lsname = ( linearSolveStrategyName.length()
00381              ? linearSolveStrategyName
00382              : this->getLinearSolveStrategyName() );
00383 #ifdef THYRA_DEFAULT_REAL_LINEAR_SOLVER_BUILDER_DUMP
00384   std::cout << "\nlsname = \"" << lsname << "\"\n";
00385 #endif
00386 
00387   // Get the index of this linear solver strategy (this will validate!)
00388   const int
00389     ls_idx = lowsfValidator_->getIntegralValue(lsname, LinearSolverType_name);
00390 
00391   // Create the uninitialized LOWSFB object
00392   RCP<Thyra::LinearOpWithSolveFactoryBase<double> >
00393     lowsf = lowsfArray_[ls_idx]->create();
00394 
00395   // First, set the preconditioner factory and its parameters
00396   if(lowsf->acceptsPreconditionerFactory()) {
00397     const std::string &pfName = this->getPreconditionerStrategyName();
00398     RCP<Thyra::PreconditionerFactoryBase<double> >
00399       pf = this->createPreconditioningStrategy(pfName);
00400     if(pf.get())
00401       lowsf->setPreconditionerFactory(pf,pfName);
00402   }
00403 
00404   // Now set the parameters for the linear solver (some of which might
00405   // override some preconditioner factory parameters).
00406   lowsf->setParameterList(
00407     sublist(sublist(paramList_, LinearSolverTypes_name), lsname));
00408   //
00409   if (enableDelayedSolverConstruction_) {
00410     return Teuchos::rcp(
00411       new Thyra::DelayedLinearOpWithSolveFactory<double>(lowsf)
00412       );
00413   }
00414 
00415   return lowsf;
00416 
00417 }
00418 
00419 
00420 RCP<Thyra::PreconditionerFactoryBase<double> >
00421 DefaultLinearSolverBuilder::createPreconditioningStrategy(
00422   const std::string &preconditioningStrategyName
00423   ) const
00424 {
00425   justInTimeInitialize();
00426 
00427   // Get the name of the preconditioning strategy
00428   const std::string
00429     pfname = ( preconditioningStrategyName.length()
00430              ? preconditioningStrategyName
00431              : this->getPreconditionerStrategyName() );
00432   RCP<Thyra::PreconditionerFactoryBase<double> >
00433     pf = Teuchos::null;
00434 
00435   // Get the index of this preconditioning strategy (this will validate!)
00436   const int
00437     pf_idx = pfValidator_->getIntegralValue(pfname, PreconditionerType_name);
00438   if( pf_idx != 0 ) {
00439     pf = pfArray_[pf_idx-1]->create(); // We offset by -1 since "None" is first!
00440     pf->setParameterList(
00441       sublist(sublist(paramList_, PreconditionerTypes_name), pfname));
00442   }
00443 
00444   return pf;
00445 
00446 }
00447 
00448 
00449 // private
00450 
00451 
00452 void DefaultLinearSolverBuilder::initializeDefaults()
00453 {
00454 
00455   using Teuchos::rcp;
00456   using Teuchos::abstractFactoryStd;
00457 
00458   defaultLOWSF_ = "";
00459   defaultPF_ = None_name;
00460   validLowsfNames_.resize(0);
00461   validPfNames_.resize(0);
00462   validPfNames_.push_back(None_name); // This will offset everything!
00463 
00464   //
00465   // Linear Solvers
00466   //
00467 
00468 #ifdef HAVE_STRATIMIKOS_BELOS
00469   setLinearSolveStrategyFactory(
00470     abstractFactoryStd<Thyra::LinearOpWithSolveFactoryBase<double>,
00471     Thyra::BelosLinearOpWithSolveFactory<double> >(),
00472     "Belos", true
00473     );
00474 #endif
00475 
00476 #ifdef HAVE_STRATIMIKOS_AMESOS
00477   setLinearSolveStrategyFactory(
00478     abstractFactoryStd<Thyra::LinearOpWithSolveFactoryBase<double>,
00479     Thyra::AmesosLinearOpWithSolveFactory>(),
00480     "Amesos", true
00481     );
00482 #endif
00483 
00484 #ifdef HAVE_STRATIMIKOS_AZTECOO
00485   setLinearSolveStrategyFactory(
00486     abstractFactoryStd<Thyra::LinearOpWithSolveFactoryBase<double>,
00487     Thyra::AztecOOLinearOpWithSolveFactory>(),
00488     "AztecOO", true
00489     );
00490 #endif
00491 
00492 #ifdef HAVE_STRATIMIKOS_AMESOS
00493   if (Teuchos::GlobalMPISession::getNProc() == 1) {
00494     setDefaultLinearSolveStrategyFactoryName("Amesos");
00495   }
00496 #endif
00497 
00498   // Note: ABove, the last LOWSF object set will be the default unless we are
00499   // on multiple processors!
00500 
00501   //
00502   // Preconditioners
00503   //
00504 
00505 #ifdef HAVE_STRATIMIKOS_ML
00506   setPreconditioningStrategyFactory(
00507     abstractFactoryStd<Thyra::PreconditionerFactoryBase<double>,
00508     Thyra::MLPreconditionerFactory>(),
00509     "ML", true
00510     );
00511 #endif
00512 
00513 #ifdef HAVE_STRATIMIKOS_IFPACK
00514   setPreconditioningStrategyFactory(
00515     abstractFactoryStd<Thyra::PreconditionerFactoryBase<double>,
00516     Thyra::IfpackPreconditionerFactory>(),
00517     "Ifpack", true
00518     );
00519 #endif
00520 
00521   // Note: Above, the last PF object set will be the default!
00522 
00523 }
00524 
00525 
00526 void DefaultLinearSolverBuilder::justInTimeInitialize() const
00527 {
00528   paramList_.assert_not_null();
00529   if (is_null(validParamList_)) {
00530     // Create the validators
00531     this->getValidParameters();
00532   }
00533 }
00534 
00535 
00536 
00537 } // namespace Stratimikos
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends