Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Thyra_MLPreconditionerFactory.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 #include "Thyra_MLPreconditionerFactory.hpp"
00043 
00044 #include "Thyra_EpetraOperatorViewExtractorStd.hpp"
00045 #include "Thyra_EpetraLinearOp.hpp"
00046 #include "Thyra_DefaultPreconditioner.hpp"
00047 #include "ml_MultiLevelPreconditioner.h"
00048 #include "ml_MultiLevelOperator.h"
00049 #include "ml_ValidateParameters.h"
00050 #include "Epetra_RowMatrix.h"
00051 #include "Teuchos_StandardParameterEntryValidators.hpp"
00052 #include "Teuchos_dyn_cast.hpp"
00053 #include "Teuchos_TimeMonitor.hpp"
00054 #include "Teuchos_implicit_cast.hpp"
00055 #include "Teuchos_ValidatorXMLConverterDB.hpp"
00056 #include "Teuchos_StaticSetupMacro.hpp"
00057 #include "Teuchos_iostream_helpers.hpp"
00058 
00059 
00060 namespace {
00061 
00062 
00063 enum EMLProblemType {
00064   ML_PROBTYPE_NONE,
00065   ML_PROBTYPE_SMOOTHED_AGGREGATION, 
00066   ML_PROBTYPE_DOMAIN_DECOMPOSITION,
00067   ML_PROBTYPE_DOMAIN_DECOMPOSITION_ML,
00068   ML_PROBTYPE_MAXWELL
00069 };
00070 const std::string BaseMethodDefaults_valueNames_none = "none";
00071 const Teuchos::Array<std::string> BaseMethodDefaults_valueNames
00072 = Teuchos::tuple<std::string>(
00073   BaseMethodDefaults_valueNames_none,
00074   "SA", 
00075   "DD",
00076   "DD-ML",
00077   "maxwell"
00078   );
00079 
00080 
00081 TEUCHOS_ENUM_INPUT_STREAM_OPERATOR(EMLProblemType)
00082 
00083 
00084 TEUCHOS_STATIC_SETUP()
00085 {
00086   TEUCHOS_ADD_STRINGTOINTEGRALVALIDATOR_CONVERTER(EMLProblemType);
00087 }
00088 
00089 const std::string BaseMethodDefaults_name = "Base Method Defaults";
00090 const std::string BaseMethodDefaults_default = "SA";
00091 Teuchos::RCP<
00092   Teuchos::StringToIntegralParameterEntryValidator<EMLProblemType>
00093   >
00094 BaseMethodDefaults_validator;
00095 
00096 const std::string ReuseFineLevelSmoother_name = "Reuse Fine Level Smoother";
00097 const bool ReuseFineLevelSmoother_default = false;
00098   
00099 const std::string MLSettings_name = "ML Settings";
00100 
00101 
00102 } // namespace
00103 
00104 
00105 namespace Thyra {
00106 
00107 
00108 using Teuchos::RCP;
00109 using Teuchos::ParameterList;
00110 
00111 
00112 // Constructors/initializers/accessors
00113 
00114   
00115 MLPreconditionerFactory::MLPreconditionerFactory()
00116   :epetraFwdOpViewExtractor_(Teuchos::rcp(new EpetraOperatorViewExtractorStd()))
00117 {}
00118 
00119 
00120 // Overridden from PreconditionerFactoryBase
00121 
00122 
00123 bool MLPreconditionerFactory::isCompatible(
00124   const LinearOpSourceBase<double> &fwdOpSrc
00125   ) const
00126 {
00127   using Teuchos::outArg;
00128   Teuchos::RCP<const Epetra_Operator> epetraFwdOp;
00129   EOpTransp epetraFwdOpTransp;
00130   EApplyEpetraOpAs epetraFwdOpApplyAs;
00131   EAdjointEpetraOp epetraFwdOpAdjointSupport;
00132   double epetraFwdOpScalar;
00133   Teuchos::RCP<const LinearOpBase<double> >
00134     fwdOp = fwdOpSrc.getOp();
00135   epetraFwdOpViewExtractor_->getEpetraOpView(
00136     fwdOp,
00137     outArg(epetraFwdOp),outArg(epetraFwdOpTransp),
00138     outArg(epetraFwdOpApplyAs),
00139     outArg(epetraFwdOpAdjointSupport),
00140     outArg(epetraFwdOpScalar)
00141     );
00142   if( !dynamic_cast<const Epetra_RowMatrix*>(&*epetraFwdOp) )
00143     return false;
00144   return true;
00145 }
00146 
00147 
00148 bool MLPreconditionerFactory::applySupportsConj(EConj conj) const
00149 {
00150   return true;
00151 }
00152 
00153 
00154 bool MLPreconditionerFactory::applyTransposeSupportsConj(EConj conj) const
00155 {
00156   return false; // See comment below
00157 }
00158 
00159 
00160 RCP<PreconditionerBase<double> >
00161 MLPreconditionerFactory::createPrec() const
00162 {
00163   return Teuchos::rcp(new DefaultPreconditioner<double>());
00164 }
00165 
00166 
00167 void MLPreconditionerFactory::initializePrec(
00168   const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
00169   PreconditionerBase<double> *prec,
00170   const ESupportSolveUse supportSolveUse
00171   ) const
00172 {
00173   using Teuchos::outArg;
00174   using Teuchos::OSTab;
00175   using Teuchos::dyn_cast;
00176   using Teuchos::RCP;
00177   using Teuchos::null;
00178   using Teuchos::rcp;
00179   using Teuchos::rcp_dynamic_cast;
00180   using Teuchos::rcp_const_cast;
00181   using Teuchos::set_extra_data;
00182   using Teuchos::get_optional_extra_data;
00183   using Teuchos::implicit_cast;
00184   Teuchos::Time totalTimer(""), timer("");
00185   totalTimer.start(true);
00186   const RCP<Teuchos::FancyOStream> out = this->getOStream();
00187   const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00188   Teuchos::OSTab tab(out);
00189   if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW))
00190     *out << "\nEntering Thyra::MLPreconditionerFactory::initializePrec(...) ...\n";
00191 
00192   Teuchos::RCP<const LinearOpBase<double> > fwdOp = fwdOpSrc->getOp();
00193 #ifdef _DEBUG
00194   TEUCHOS_TEST_FOR_EXCEPT(fwdOp.get()==NULL);
00195   TEUCHOS_TEST_FOR_EXCEPT(prec==NULL);
00196 #endif
00197   //
00198   // Unwrap and get the forward Epetra_Operator object
00199   //
00200   Teuchos::RCP<const Epetra_Operator> epetraFwdOp;
00201   EOpTransp epetraFwdOpTransp;
00202   EApplyEpetraOpAs epetraFwdOpApplyAs;
00203   EAdjointEpetraOp epetraFwdOpAdjointSupport;
00204   double epetraFwdOpScalar;
00205   epetraFwdOpViewExtractor_->getEpetraOpView(
00206     fwdOp,outArg(epetraFwdOp),outArg(epetraFwdOpTransp),outArg(epetraFwdOpApplyAs),
00207     outArg(epetraFwdOpAdjointSupport),outArg(epetraFwdOpScalar)
00208                                              );
00209   // Validate what we get is what we need
00210   RCP<const Epetra_RowMatrix>
00211     epetraFwdRowMat = rcp_dynamic_cast<const Epetra_RowMatrix>(epetraFwdOp,true);
00212   TEUCHOS_TEST_FOR_EXCEPTION(
00213     epetraFwdOpApplyAs != EPETRA_OP_APPLY_APPLY, std::logic_error
00214     ,"Error, incorrect apply mode for an Epetra_RowMatrix"
00215     );
00216 
00217   //
00218   // Get the concrete preconditioner object
00219   //
00220   DefaultPreconditioner<double>
00221     *defaultPrec = &Teuchos::dyn_cast<DefaultPreconditioner<double> >(*prec);
00222   //
00223   // Get the EpetraLinearOp object that is used to implement the preconditoner linear op
00224   //
00225   RCP<EpetraLinearOp>
00226     epetra_precOp = rcp_dynamic_cast<EpetraLinearOp>(defaultPrec->getNonconstUnspecifiedPrecOp(),true);
00227   //
00228   // Get the embedded ML_Epetra::MultiLevelPreconditioner object if it exists
00229   //
00230   Teuchos::RCP<ML_Epetra::MultiLevelPreconditioner> ml_precOp;
00231   if(epetra_precOp.get())
00232     ml_precOp = rcp_dynamic_cast<ML_Epetra::MultiLevelPreconditioner>(epetra_precOp->epetra_op(),true);
00233   //
00234   // Get the attached forward operator if it exists and make sure that it matches
00235   //
00236   if(ml_precOp!=Teuchos::null) {
00237     // Get the forward operator and make sure that it matches what is
00238     // already being used!
00239     const Epetra_RowMatrix & rm = ml_precOp->RowMatrix();
00240    
00241     TEUCHOS_TEST_FOR_EXCEPTION(
00242        &rm!=&*epetraFwdRowMat, std::logic_error
00243        ,"ML requires Epetra_RowMatrix to be the same for each initialization of the preconditioner"
00244        );
00245   }
00246   //
00247   // Perform initialization if needed
00248   //
00249   const bool startingOver = (ml_precOp.get() == NULL);
00250   if(startingOver) 
00251   {
00252     if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00253       *out << "\nCreating the initial ML_Epetra::MultiLevelPreconditioner object...\n";
00254     timer.start(true);
00255     // Create the initial preconditioner: DO NOT compute it yet
00256     ml_precOp = rcp(
00257       new ML_Epetra::MultiLevelPreconditioner(
00258         *epetraFwdRowMat, paramList_->sublist(MLSettings_name),false
00259         )
00260       );
00261     
00262     timer.stop();
00263     if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00264       OSTab(out).o() <<"> Creation time = "<<timer.totalElapsedTime()<<" sec\n";
00265     // RAB: Above, I am just passing a string to ML::Create(...) in order
00266     // get this code written.  However, in the future, it would be good to
00267     // copy the contents of what is in ML::Create(...) into a local
00268     // function and then use switch(...) to create the initial
00269     // ML_Epetra::MultiLevelPreconditioner object.  This would result in better validation
00270     // and faster code.
00271     // Set parameters if the list exists
00272     if(paramList_.get())
00273       TEUCHOS_TEST_FOR_EXCEPT(
00274         0!=ml_precOp->SetParameterList(paramList_->sublist(MLSettings_name))
00275         );
00276     // Initialize the structure for the preconditioner
00277     //        TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->Initialize());
00278   }
00279   //
00280   // Attach the epetraFwdOp to the ml_precOp to guarantee that it will not go away
00281   //
00282   set_extra_data(epetraFwdOp, "IFPF::epetraFwdOp", Teuchos::inOutArg(ml_precOp),
00283     Teuchos::POST_DESTROY, false);
00284   //
00285   // Update the factorization
00286   //
00287   if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00288     *out << "\nComputing the preconditioner ...\n";
00289   timer.start(true);
00290   if (startingOver) {
00291     TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->ComputePreconditioner());
00292   }
00293   else {
00294     TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->ReComputePreconditioner(paramList_->get<bool>(ReuseFineLevelSmoother_name)));
00295   }
00296   timer.stop();
00297   if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00298     OSTab(out).o() <<"=> Setup time = "<<timer.totalElapsedTime()<<" sec\n";
00299   //
00300   // Compute the conditioner number estimate if asked
00301   //
00302 
00303   // ToDo: Implement
00304 
00305   //
00306   // Attach fwdOp to the ml_precOp
00307   //
00308   set_extra_data(fwdOp, "IFPF::fwdOp", Teuchos::inOutArg(ml_precOp),
00309     Teuchos::POST_DESTROY, false);
00310   //
00311   // Initialize the output EpetraLinearOp
00312   //
00313   if(startingOver) {
00314     epetra_precOp = rcp(new EpetraLinearOp);
00315   }
00316   epetra_precOp->initialize(
00317     ml_precOp
00318     ,epetraFwdOpTransp
00319     ,EPETRA_OP_APPLY_APPLY_INVERSE
00320     ,EPETRA_OP_ADJOINT_UNSUPPORTED  // ToDo: Look into adjoints again.
00321     );
00322   //
00323   // Initialize the preconditioner
00324   //
00325   defaultPrec->initializeUnspecified(
00326     Teuchos::rcp_implicit_cast<LinearOpBase<double> >(epetra_precOp)
00327     );
00328   totalTimer.stop();
00329   if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00330     *out << "\nTotal time in MLPreconditionerFactory = "<<totalTimer.totalElapsedTime()<<" sec\n";
00331   if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW))
00332     *out << "\nLeaving Thyra::MLPreconditionerFactory::initializePrec(...) ...\n";
00333 }
00334 
00335 
00336 void MLPreconditionerFactory::uninitializePrec(
00337   PreconditionerBase<double> *prec,
00338   Teuchos::RCP<const LinearOpSourceBase<double> > *fwdOp,
00339   ESupportSolveUse *supportSolveUse
00340   ) const
00341 {
00342   TEUCHOS_TEST_FOR_EXCEPT(true);
00343 }
00344 
00345 
00346 // Overridden from ParameterListAcceptor
00347 
00348 
00349 void MLPreconditionerFactory::setParameterList(
00350   Teuchos::RCP<ParameterList> const& paramList
00351   )
00352 {
00353   TEUCHOS_TEST_FOR_EXCEPT(paramList.get()==NULL);
00354   paramList->validateParameters(*this->getValidParameters(),0);
00355   paramList_ = paramList;
00356 
00357   // set default for reuse of fine level smoother
00358   if(!paramList_->isType<bool>(ReuseFineLevelSmoother_name))
00359     paramList_->set<bool>(ReuseFineLevelSmoother_name,ReuseFineLevelSmoother_default);
00360 
00361   const EMLProblemType
00362     defaultType = BaseMethodDefaults_validator->getIntegralValue(
00363       *paramList_,BaseMethodDefaults_name,BaseMethodDefaults_default
00364       );
00365   if( ML_PROBTYPE_NONE != defaultType ) {
00366     const std::string
00367       defaultTypeStr = BaseMethodDefaults_valueNames[defaultType];
00368     Teuchos::ParameterList defaultParams;
00369     TEUCHOS_TEST_FOR_EXCEPTION(
00370       0!=ML_Epetra::SetDefaults(defaultTypeStr,defaultParams)
00371       ,Teuchos::Exceptions::InvalidParameterValue
00372       ,"Error, the ML problem type \"" << defaultTypeStr << "\' is not recognized by ML!"
00373       );
00374     // Note, the only way the above exception message could be generated is if
00375     // a default problem type was removed from ML_Epetra::SetDefaults(...).
00376     // When a new problem type is added to this function, it must be added to
00377     // our enum EMLProblemType along with associated objects ...  In other
00378     // words, this adapter must be maintained as ML is maintained.  An
00379     // alternative design would be to just pass in whatever string to this
00380     // function.  This would improve maintainability but it would not generate
00381     // very good error messages when a bad string was passed in.  Currently,
00382     // the error message attached to the exception will contain the list of
00383     // valid problem types.
00384     paramList_->sublist(MLSettings_name).setParametersNotAlreadySet(
00385       defaultParams);
00386   }
00387 #ifdef TEUCHOS_DEBUG
00388   paramList->validateParameters(*this->getValidParameters(),0);
00389 #endif
00390 }
00391 
00392 
00393 RCP<ParameterList>
00394 MLPreconditionerFactory::getNonconstParameterList()
00395 {
00396   return paramList_;
00397 }
00398 
00399 
00400 RCP<ParameterList>
00401 MLPreconditionerFactory::unsetParameterList()
00402 {
00403   Teuchos::RCP<ParameterList> _paramList = paramList_;
00404   paramList_ = Teuchos::null;
00405   return _paramList;
00406 }
00407 
00408 
00409 RCP<const ParameterList>
00410 MLPreconditionerFactory::getParameterList() const
00411 {
00412   return paramList_;
00413 }
00414 
00415 
00416 RCP<const ParameterList>
00417 MLPreconditionerFactory::getValidParameters() const
00418 {
00419 
00420   using Teuchos::rcp;
00421   using Teuchos::tuple;
00422   using Teuchos::implicit_cast;
00423   using Teuchos::rcp_implicit_cast;
00424   typedef Teuchos::ParameterEntryValidator PEV;
00425 
00426   static RCP<const ParameterList> validPL;
00427 
00428   if(is_null(validPL)) {
00429 
00430     RCP<ParameterList>
00431       pl = rcp(new ParameterList());
00432 
00433     BaseMethodDefaults_validator = rcp(
00434       new Teuchos::StringToIntegralParameterEntryValidator<EMLProblemType>(
00435         BaseMethodDefaults_valueNames,
00436         tuple<std::string>(
00437           "Do not set any default parameters",
00438           "Set default parameters for a smoothed aggregation method",
00439           "Set default parameters for a domain decomposition method",
00440           "Set default parameters for a domain decomposition method special to ML",
00441           "Set default parameters for a Maxwell-type of linear operator"
00442           ),
00443         tuple<EMLProblemType>(
00444           ML_PROBTYPE_NONE,
00445           ML_PROBTYPE_SMOOTHED_AGGREGATION,
00446           ML_PROBTYPE_DOMAIN_DECOMPOSITION,
00447           ML_PROBTYPE_DOMAIN_DECOMPOSITION_ML,
00448           ML_PROBTYPE_MAXWELL
00449           ),
00450         BaseMethodDefaults_name
00451         )
00452       );
00453 
00454     pl->set(BaseMethodDefaults_name,BaseMethodDefaults_default,
00455       "Select the default method type which also sets parameter defaults\n"
00456       "in the sublist \"" + MLSettings_name + "\"!",
00457       rcp_implicit_cast<const PEV>(BaseMethodDefaults_validator)
00458       );
00459 
00460     pl->set(ReuseFineLevelSmoother_name,ReuseFineLevelSmoother_default,
00461       "Enables/disables the reuse of the fine level smoother.");
00462 
00463 /* 2007/07/02: rabartl:  The statement below should be the correct way to
00464  * get the list of valid parameters but it seems to be causing problems so
00465  * I am commenting it out for now.
00466  */
00467 /*
00468     pl->sublist(
00469       MLSettings_name, false,
00470       "Parameters directly accepted by ML_Epetra interface."
00471       ).setParameters(*rcp(ML_Epetra::GetValidMLPParameters()));
00472 */
00473     
00474     {
00475       ParameterList &mlSettingsPL = pl->sublist(
00476         MLSettings_name, false,
00477         "Sampling of the parameters directly accepted by ML\n"
00478         "This list of parameters is generated by combining all of\n"
00479         "the parameters set for all of the default problem types supported\n"
00480         "by ML.  Therefore, do not assume these parameters are at values that\n"
00481         "are reasonable to ML.  This list is just to give a sense of some of\n"
00482         "the parameters that ML accepts.  Consult ML documentation on how to\n"
00483         "set these parameters.  Also, you can print the parameter list after\n"
00484         "it is used and see what defaults where set for each default problem\n"
00485         "type.  Warning! the parameters in this sublist are currently *not*\n"
00486         "being validated by ML!"
00487         );
00488       //std::cout << "\nMLSettings doc before = " << pl->getEntryPtr(MLSettings_name)->docString() << "\n";
00489       { // Set of valid parameters (but perhaps not acceptable values)
00490         for (
00491           int i = 0;
00492           i < implicit_cast<int>(BaseMethodDefaults_valueNames.size());
00493           ++i
00494           )
00495         {
00496           ParameterList defaultParams;
00497           const std::string defaultTypeStr = BaseMethodDefaults_valueNames[i];
00498           if (defaultTypeStr != BaseMethodDefaults_valueNames_none) {
00499             TEUCHOS_TEST_FOR_EXCEPTION(
00500               0!=ML_Epetra::SetDefaults(defaultTypeStr,defaultParams)
00501               ,Teuchos::Exceptions::InvalidParameterValue
00502               ,"Error, the ML problem type \"" << defaultTypeStr
00503               << "\' is not recognized by ML!"
00504               );
00505             mlSettingsPL.setParameters(defaultParams);
00506           }
00507         }
00508       }
00509     }
00510 
00511     validPL = pl;
00512 
00513   }
00514 
00515   return validPL;
00516 
00517 }
00518 
00519 
00520 // Public functions overridden from Teuchos::Describable
00521 
00522 
00523 std::string MLPreconditionerFactory::description() const
00524 {
00525   std::ostringstream oss;
00526   oss << "Thyra::MLPreconditionerFactory";
00527   return oss.str();
00528 }
00529 
00530 
00531 } // namespace Thyra
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines