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
00079   ,const std::string   &extraParamsXmlString
00080   ,const std::string   &paramsUsedXmlOutFileName
00081   ,const std::string   &paramsXmlFileNameOption
00082   ,const std::string   &extraParamsXmlStringOption
00083   ,const std::string   &paramsUsedXmlOutFileNameOption
00084   )
00085   :paramsXmlFileName_(paramsXmlFileName)
00086   ,extraParamsXmlString_(extraParamsXmlString)
00087   ,paramsUsedXmlOutFileName_(paramsUsedXmlOutFileName)
00088   ,paramsXmlFileNameOption_(paramsXmlFileNameOption)
00089   ,extraParamsXmlStringOption_(extraParamsXmlStringOption)
00090   ,paramsUsedXmlOutFileNameOption_(paramsUsedXmlOutFileNameOption)
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   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   if(!paramList_.get()) {
00177     paramList_ = Teuchos::parameterList("DefaultLinearSolverBuilder");
00178   }
00179   if (paramsXmlFileName().length()) {
00180     if(out) *out
00181       << "\nReading parameters from XML file \""<<paramsXmlFileName()<<"\" ...\n";
00182     Teuchos::updateParametersFromXmlFile(paramsXmlFileName(), &*paramList_);
00183   }
00184   if (extraParamsXmlString().length()) {
00185     if(out) *out
00186       << "\nAppending extra parameters from the XML string \""
00187       <<extraParamsXmlString()<<"\" ...\n";
00188     Teuchos::updateParametersFromXmlString(extraParamsXmlString(), &*paramList_);
00189   }
00190   setParameterList(paramList_);
00191 }
00192 
00193 
00194 void DefaultLinearSolverBuilder::writeParamsFile(
00195   const Thyra::LinearOpWithSolveFactoryBase<double> &lowsFactory,
00196   const std::string &outputXmlFileName
00197   ) const
00198 {
00199   justInTimeInitialize();
00200   const std::string xmlOutputFile =
00201     ( outputXmlFileName.length() ? outputXmlFileName : paramsUsedXmlOutFileName() );
00202   if (xmlOutputFile.length()) {
00203     Teuchos::writeParameterListToXmlFile(*paramList_, xmlOutputFile);
00204   }
00205 }
00206 
00207 
00208 std::string
00209 DefaultLinearSolverBuilder::getLinearSolveStrategyName() const
00210 {
00211   justInTimeInitialize();
00212   return lowsfValidator_->getStringValue(*paramList_, LinearSolverType_name,
00213     defaultLOWSF_);
00214 }
00215 
00216 
00217 std::string
00218 DefaultLinearSolverBuilder::getPreconditionerStrategyName() const
00219 {
00220   justInTimeInitialize();
00221   return pfValidator_->getStringValue(*paramList_, PreconditionerType_name,
00222     defaultPF_);
00223 }
00224 
00225 
00226 // Overridden from ParameterListAcceptor
00227 
00228 
00229 void DefaultLinearSolverBuilder::setParameterList(
00230   RCP<Teuchos::ParameterList> const& paramList
00231   )
00232 {
00233   TEST_FOR_EXCEPT(is_null(paramList));
00234   paramList->validateParameters(*this->getValidParameters());
00235   paramList_ = paramList;
00236   enableDelayedSolverConstruction_ = paramList_->get(
00237     EnableDelayedSolverConstruction_name, EnableDelayedSolverConstruction_default );
00238 }
00239 
00240 
00241 RCP<Teuchos::ParameterList>
00242 DefaultLinearSolverBuilder::getNonconstParameterList()
00243 {
00244   return paramList_;
00245 }
00246 
00247 
00248 RCP<Teuchos::ParameterList>
00249 DefaultLinearSolverBuilder::unsetParameterList()
00250 {
00251   RCP<Teuchos::ParameterList> _paramList = paramList_;
00252   paramList_ = Teuchos::null;
00253   return _paramList;
00254 }
00255 
00256 
00257 RCP<const Teuchos::ParameterList>
00258 DefaultLinearSolverBuilder::getParameterList() const
00259 {
00260   return paramList_;
00261 }
00262 
00263 
00264 RCP<const Teuchos::ParameterList>
00265 DefaultLinearSolverBuilder::getValidParameters() const
00266 {
00267   using Teuchos::rcp_implicit_cast;
00268   typedef Teuchos::ParameterEntryValidator PEV;
00269   if (is_null(validParamList_)) {
00270     RCP<Teuchos::ParameterList>
00271       validParamList = Teuchos::rcp(new Teuchos::ParameterList);
00272     // Linear Solver Types
00273     lowsfValidator_ = Teuchos::rcp(
00274       new Teuchos::StringToIntegralParameterEntryValidator<int>(
00275         validLowsfNames_,LinearSolverType_name
00276         )
00277       );
00278     validParamList->set(
00279       LinearSolverType_name, defaultLOWSF_,
00280       (std::string("Determines the type of linear solver that will be used.\n")
00281         + "The parameters for each solver type are specified in the sublist \""
00282         + LinearSolverTypes_name + "\"").c_str(),
00283       rcp_implicit_cast<const PEV>(lowsfValidator_)
00284       );
00285     Teuchos::ParameterList &linearSolverTypesSL = validParamList->sublist(
00286       LinearSolverTypes_name,false,
00287       "Sublists for each of the linear solver types set using the parameter\n"
00288       "\"" + LinearSolverType_name + "\".  Note that the options for each\n"
00289       "linear solver type given below will only be used if linear solvers\n"
00290       "of that type are created.  It is fine to list parameter sublists for\n"
00291       "linear solver types that are not used."
00292       );
00293     for( int i = 0; i < static_cast<int>(lowsfArray_.size()); ++i ) {
00294       const std::string
00295         &lsname = validLowsfNames_[i];
00296       const RCP<Thyra::LinearOpWithSolveFactoryBase<double> >
00297         lowsf = lowsfArray_[i]->create();
00298       linearSolverTypesSL.sublist(lsname).setParameters(*lowsf->getValidParameters()
00299         ).disableRecursiveValidation();
00300     }
00301     // Preconditioner Type
00302     pfValidator_ = Teuchos::rcp(
00303       new Teuchos::StringToIntegralParameterEntryValidator<int>(
00304         validPfNames_, PreconditionerType_name ) );
00305     validParamList->set(
00306       PreconditionerType_name, defaultPF_,
00307       (std::string("Determines the type of preconditioner that will be used.\n")
00308         + "This option is only meaningful for linear solvers that accept preconditioner"
00309         + " factory objects!\n"
00310         + "The parameters for each preconditioner are specified in the sublist \""
00311         + PreconditionerTypes_name + "\"").c_str(),
00312       rcp_implicit_cast<const PEV>(pfValidator_)
00313       );
00314     Teuchos::ParameterList &precTypesSL = validParamList->sublist(
00315         PreconditionerTypes_name,false,
00316         "Sublists for each of the preconditioner types set using the parameter\n"
00317         "\"" + PreconditionerType_name + "\".  Note that the options for each\n"
00318         "preconditioner type given below will only be used if preconditioners\n"
00319         "of that type are created.  It is fine to list parameter sublists for\n"
00320         "preconditioner types that are not used."
00321         );
00322     for( int i = 0; i < static_cast<int>(pfArray_.size()); ++i ) {
00323       const std::string
00324         &pfname = validPfNames_[i+1]; // "None" is the 0th entry!
00325       const RCP<Thyra::PreconditionerFactoryBase<double> >
00326         pf = pfArray_[i]->create();
00327       precTypesSL.sublist(pfname).setParameters(*pf->getValidParameters()
00328         ).disableRecursiveValidation();
00329     }
00330     // 
00331     validParamList->set(
00332       EnableDelayedSolverConstruction_name, EnableDelayedSolverConstruction_default,
00333       "When this option is set to true, the linear solver factory will be wrapped\n"
00334       "in a delayed evaluation Decorator factory object.  This results in a delay\n"
00335       "in the creation of a linear solver (and the associated preconditioner) until\n"
00336       "the first solve is actually performed.  This helps in cases where it is not\n"
00337       "known a-priori if a linear solve will be needed on a given linear operator and\n"
00338       "therefore can significantly improve performance for some types of algorithms\n"
00339       "such as NOX and LOCA."
00340       );
00341     //
00342     validParamList_ = validParamList;
00343   }
00344   return validParamList_;
00345 }
00346 
00347   
00348 // Overridden from LinearSolverBuilderBase.
00349 
00350 
00351 RCP<Thyra::LinearOpWithSolveFactoryBase<double> >
00352 DefaultLinearSolverBuilder::createLinearSolveStrategy(
00353   const std::string &linearSolveStrategyName
00354   ) const
00355 {
00356   justInTimeInitialize();
00357 
00358   // Get the name of the linear solve strategy
00359 #ifdef THYRA_DEFAULT_REAL_LINEAR_SOLVER_BUILDER_DUMP
00360   std::cout << "\nEntering DefaultLinearSolverBuilder"
00361             << "::createLinearSolveStrategy(...) ...\n";
00362   std::cout << "\nlinearSolveStrategyName = \""
00363             << linearSolveStrategyName << "\"\n";
00364   std::cout << "\nlinearSolveStrategyName.length() = "
00365             << linearSolveStrategyName.length() << "\n";
00366   std::cout << "\ndefaultLOWSF_ = \"" << defaultLOWSF_ << "\"\n";
00367   std::cout << "\nthis->getLinearSolveStrategyName() = \""
00368             << this->getLinearSolveStrategyName() << "\"\n";
00369 #endif
00370   const std::string
00371     lsname = ( linearSolveStrategyName.length()
00372              ? linearSolveStrategyName
00373              : this->getLinearSolveStrategyName() );
00374 #ifdef THYRA_DEFAULT_REAL_LINEAR_SOLVER_BUILDER_DUMP
00375   std::cout << "\nlsname = \"" << lsname << "\"\n";
00376 #endif
00377 
00378   // Get the index of this linear solver strategy (this will validate!)
00379   const int
00380     ls_idx = lowsfValidator_->getIntegralValue(lsname, LinearSolverType_name);
00381 
00382   // Create the uninitialized LOWSFB object
00383   RCP<Thyra::LinearOpWithSolveFactoryBase<double> >
00384     lowsf = lowsfArray_[ls_idx]->create();
00385 
00386   // First, set the preconditioner factory and its parameters
00387   if(lowsf->acceptsPreconditionerFactory()) {
00388     const std::string &pfName = this->getPreconditionerStrategyName();
00389     RCP<Thyra::PreconditionerFactoryBase<double> >
00390       pf = this->createPreconditioningStrategy(pfName);
00391     if(pf.get())
00392       lowsf->setPreconditionerFactory(pf,pfName);
00393   }
00394 
00395   // Now set the parameters for the linear solver (some of which might
00396   // override some preconditioner factory parameters).
00397   lowsf->setParameterList(
00398     sublist(sublist(paramList_, LinearSolverTypes_name), lsname));
00399   //
00400   if (enableDelayedSolverConstruction_) {
00401     return Teuchos::rcp(
00402       new Thyra::DelayedLinearOpWithSolveFactory<double>(lowsf)
00403       );
00404   }
00405 
00406   return lowsf;
00407 
00408 }
00409 
00410 
00411 RCP<Thyra::PreconditionerFactoryBase<double> >
00412 DefaultLinearSolverBuilder::createPreconditioningStrategy(
00413   const std::string &preconditioningStrategyName
00414   ) const
00415 {
00416   justInTimeInitialize();
00417 
00418   // Get the name of the preconditioning strategy
00419   const std::string
00420     pfname = ( preconditioningStrategyName.length()
00421              ? preconditioningStrategyName
00422              : this->getPreconditionerStrategyName() );
00423   RCP<Thyra::PreconditionerFactoryBase<double> >
00424     pf = Teuchos::null;
00425 
00426   // Get the index of this preconditioning strategy (this will validate!)
00427   const int
00428     pf_idx = pfValidator_->getIntegralValue(pfname, PreconditionerType_name);
00429   if( pf_idx != 0 ) {
00430     pf = pfArray_[pf_idx-1]->create(); // We offset by -1 since "None" is first!
00431     pf->setParameterList(
00432       sublist(sublist(paramList_, PreconditionerTypes_name), pfname));
00433   }
00434 
00435   return pf;
00436 
00437 }
00438 
00439 
00440 // private
00441 
00442 
00443 void DefaultLinearSolverBuilder::initializeDefaults()
00444 {
00445 
00446   using Teuchos::rcp;
00447   using Teuchos::abstractFactoryStd;
00448 
00449   defaultLOWSF_ = "";
00450   defaultPF_ = None_name;
00451   validLowsfNames_.resize(0);
00452   validPfNames_.resize(0);
00453   validPfNames_.push_back(None_name); // This will offset everything!
00454 
00455   //
00456   // Linear Solvers
00457   //
00458 
00459 #ifdef HAVE_STRATIMIKOS_BELOS
00460   setLinearSolveStrategyFactory(
00461     abstractFactoryStd<Thyra::LinearOpWithSolveFactoryBase<double>,
00462     Thyra::BelosLinearOpWithSolveFactory<double> >(),
00463     "Belos", true
00464     );
00465 #endif
00466 
00467 #ifdef HAVE_STRATIMIKOS_AMESOS
00468   setLinearSolveStrategyFactory(
00469     abstractFactoryStd<Thyra::LinearOpWithSolveFactoryBase<double>,
00470     Thyra::AmesosLinearOpWithSolveFactory>(),
00471     "Amesos", true
00472     );
00473 #endif
00474 
00475 #ifdef HAVE_STRATIMIKOS_AZTECOO
00476   setLinearSolveStrategyFactory(
00477     abstractFactoryStd<Thyra::LinearOpWithSolveFactoryBase<double>,
00478     Thyra::AztecOOLinearOpWithSolveFactory>(),
00479     "AztecOO", true
00480     );
00481 #endif
00482 
00483 #ifdef HAVE_STRATIMIKOS_AMESOS
00484   if (Teuchos::GlobalMPISession::getNProc() == 1) {
00485     setDefaultLinearSolveStrategyFactoryName("Amesos");
00486   }
00487 #endif
00488 
00489   // Note: ABove, the last LOWSF object set will be the default unless we are
00490   // on multiple processors!
00491 
00492   //
00493   // Preconditioners
00494   //
00495 
00496 #ifdef HAVE_STRATIMIKOS_ML
00497   setPreconditioningStrategyFactory(
00498     abstractFactoryStd<Thyra::PreconditionerFactoryBase<double>,
00499     Thyra::MLPreconditionerFactory>(),
00500     "ML", true
00501     );
00502 #endif
00503 
00504 #ifdef HAVE_STRATIMIKOS_IFPACK
00505   setPreconditioningStrategyFactory(
00506     abstractFactoryStd<Thyra::PreconditionerFactoryBase<double>,
00507     Thyra::IfpackPreconditionerFactory>(),
00508     "Ifpack", true
00509     );
00510 #endif
00511 
00512   // Note: Above, the last PF object set will be the default!
00513 
00514 }
00515 
00516 
00517 void DefaultLinearSolverBuilder::justInTimeInitialize() const
00518 {
00519   paramList_.assert_not_null();
00520   if (is_null(validParamList_)) {
00521     // Create the validators
00522     this->getValidParameters();
00523   }
00524 }
00525 
00526 
00527 
00528 } // namespace Stratimikos
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends