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