Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Thyra_IfpackPreconditionerFactory.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_IfpackPreconditionerFactory.hpp"
00043 #include "Thyra_EpetraOperatorViewExtractorStd.hpp"
00044 #include "Thyra_EpetraLinearOp.hpp"
00045 #include "Thyra_DefaultPreconditioner.hpp"
00046 #include "Ifpack_ValidParameters.h"
00047 #include "Ifpack_Preconditioner.h"
00048 #include "Ifpack.h"
00049 #include "Epetra_RowMatrix.h"
00050 #include "Teuchos_TimeMonitor.hpp"
00051 #include "Teuchos_dyn_cast.hpp"
00052 #include "Teuchos_implicit_cast.hpp"
00053 #include "Teuchos_StandardParameterEntryValidators.hpp"
00054 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
00055 #include "Teuchos_ValidatorXMLConverterDB.hpp"
00056 #include "Teuchos_StaticSetupMacro.hpp"
00057 
00058 
00059 namespace {
00060 
00061 Teuchos::RCP<Teuchos::Time> overallTimer, creationTimer, factorizationTimer;
00062 
00063 const std::string Ifpack_name = "Ifpack";
00064 
00065 const std::string IfpackSettings_name = "Ifpack Settings";
00066 
00067 const std::string PrecType_name = "Prec Type";
00068 Teuchos::RCP<Teuchos::StringToIntegralParameterEntryValidator<Ifpack::EPrecType> >
00069 precTypeValidator; // Will be setup below!
00070 const Ifpack::EPrecType PrecType_default = Ifpack::ILU;
00071 const std::string PrecTypeName_default = Ifpack::precTypeNames[PrecType_default];
00072 
00073 const std::string Overlap_name = "Overlap";
00074 const int Overlap_default = 0;
00075 
00076 
00077 TEUCHOS_STATIC_SETUP()
00078 {
00079   TEUCHOS_ADD_STRINGTOINTEGRALVALIDATOR_CONVERTER(Ifpack::EPrecType);
00080 }
00081 
00082 
00083 } // namespace
00084 
00085 namespace Thyra {
00086 
00087 // Constructors/initializers/accessors
00088 
00089 IfpackPreconditionerFactory::IfpackPreconditionerFactory()
00090   :epetraFwdOpViewExtractor_(Teuchos::rcp(new EpetraOperatorViewExtractorStd()))
00091   ,precType_(PrecType_default)
00092   ,overlap_(Overlap_default)
00093 {
00094   initializeTimers();
00095   getValidParameters(); // Make sure validators get created!
00096 }
00097 
00098 // Overridden from PreconditionerFactoryBase
00099 
00100 bool IfpackPreconditionerFactory::isCompatible(
00101   const LinearOpSourceBase<double> &fwdOpSrc
00102   ) const
00103 {
00104   using Teuchos::outArg;
00105   Teuchos::RCP<const Epetra_Operator> epetraFwdOp;
00106   EOpTransp epetraFwdOpTransp;
00107   EApplyEpetraOpAs epetraFwdOpApplyAs;
00108   EAdjointEpetraOp epetraFwdOpAdjointSupport;
00109   double epetraFwdOpScalar;
00110   epetraFwdOpViewExtractor_->getEpetraOpView(
00111     fwdOpSrc.getOp(), 
00112     outArg(epetraFwdOp), outArg(epetraFwdOpTransp),
00113     outArg(epetraFwdOpApplyAs), outArg(epetraFwdOpAdjointSupport),
00114     outArg(epetraFwdOpScalar)
00115     );
00116   if( !dynamic_cast<const Epetra_RowMatrix*>(&*epetraFwdOp) )
00117     return false;
00118   return true;
00119 }
00120 
00121 bool IfpackPreconditionerFactory::applySupportsConj(EConj conj) const
00122 {
00123   return true;
00124 }
00125 
00126 bool IfpackPreconditionerFactory::applyTransposeSupportsConj(EConj conj) const
00127 {
00128   return false; // See comment below
00129 }
00130 
00131 Teuchos::RCP<PreconditionerBase<double> >
00132 IfpackPreconditionerFactory::createPrec() const
00133 {
00134   return Teuchos::rcp(new DefaultPreconditioner<double>());
00135 }
00136 
00137 void IfpackPreconditionerFactory::initializePrec(
00138   const Teuchos::RCP<const LinearOpSourceBase<double> >    &fwdOpSrc
00139   ,PreconditionerBase<double>                                      *prec
00140   ,const ESupportSolveUse                                           supportSolveUse
00141   ) const
00142 {
00143   using Teuchos::outArg;
00144   using Teuchos::OSTab;
00145   using Teuchos::dyn_cast;
00146   using Teuchos::RCP;
00147   using Teuchos::null;
00148   using Teuchos::rcp;
00149   using Teuchos::rcp_dynamic_cast;
00150   using Teuchos::rcp_const_cast;
00151   using Teuchos::set_extra_data;
00152   using Teuchos::get_optional_extra_data;
00153   using Teuchos::implicit_cast;
00154   Teuchos::Time totalTimer(""), timer("");
00155   totalTimer.start(true);
00156 #ifdef STRATIMIKOS_TEUCHOS_TIME_MONITOR
00157   Teuchos::TimeMonitor overallTimeMonitor(*overallTimer);
00158 #endif
00159   const Teuchos::RCP<Teuchos::FancyOStream> out       = this->getOStream();
00160   const Teuchos::EVerbosityLevel                    verbLevel = this->getVerbLevel();
00161   Teuchos::OSTab tab(out);
00162   if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW))
00163     *out << "\nEntering Thyra::IfpackPreconditionerFactory::initializePrec(...) ...\n";
00164 #ifdef TEUCHOS_DEBUG
00165   TEUCHOS_TEST_FOR_EXCEPT(fwdOpSrc.get()==NULL);
00166   TEUCHOS_TEST_FOR_EXCEPT(prec==NULL);
00167 #endif
00168   Teuchos::RCP<const LinearOpBase<double> >
00169     fwdOp = fwdOpSrc->getOp();
00170 #ifdef TEUCHOS_DEBUG
00171   TEUCHOS_TEST_FOR_EXCEPT(fwdOp.get()==NULL);
00172 #endif
00173   //
00174   // Unwrap and get the forward Epetra_Operator object
00175   //
00176   Teuchos::RCP<const Epetra_Operator> epetraFwdOp;
00177   EOpTransp epetraFwdOpTransp;
00178   EApplyEpetraOpAs epetraFwdOpApplyAs;
00179   EAdjointEpetraOp epetraFwdOpAdjointSupport;
00180   double epetraFwdOpScalar;
00181   epetraFwdOpViewExtractor_->getEpetraOpView(
00182     fwdOp,
00183     outArg(epetraFwdOp), outArg(epetraFwdOpTransp),
00184     outArg(epetraFwdOpApplyAs), outArg(epetraFwdOpAdjointSupport),
00185     outArg(epetraFwdOpScalar)
00186     );
00187   // Validate what we get is what we need
00188   RCP<const Epetra_RowMatrix>
00189     epetraFwdRowMat = rcp_dynamic_cast<const Epetra_RowMatrix>(epetraFwdOp,true);
00190   TEUCHOS_TEST_FOR_EXCEPTION(
00191     epetraFwdOpApplyAs != EPETRA_OP_APPLY_APPLY, std::logic_error
00192     ,"Error, incorrect apply mode for an Epetra_RowMatrix"
00193     );
00194   //
00195   // Get the concrete preconditioner object
00196   //
00197   DefaultPreconditioner<double>
00198     *defaultPrec = &Teuchos::dyn_cast<DefaultPreconditioner<double> >(*prec);
00199   //
00200   // Get the EpetraLinearOp object that is used to implement the preconditoner linear op
00201   //
00202   RCP<EpetraLinearOp>
00203     epetra_precOp = rcp_dynamic_cast<EpetraLinearOp>(defaultPrec->getNonconstUnspecifiedPrecOp(),true);
00204   //
00205   // Get the embedded Ifpack_Preconditioner object if it exists
00206   //
00207   Teuchos::RCP<Ifpack_Preconditioner>
00208     ifpack_precOp;
00209   if(epetra_precOp.get())
00210     ifpack_precOp = rcp_dynamic_cast<Ifpack_Preconditioner>(epetra_precOp->epetra_op(),true);
00211   //
00212   // Get the attached forward operator if it exists and make sure that it matches
00213   //
00214   if(ifpack_precOp.get()) {
00215     // ToDo: Get the forward operator and make sure that it matches what is
00216     // already being used!
00217   }
00218   //
00219   // Permform initialization if needed
00220   //
00221   //const bool startingOver = (ifpack_precOp.get() == NULL);
00222   const bool startingOver = true;
00223   // ToDo: Comment back in the above original version of startingOver to allow
00224   // for resuse.  Rob H. just pointed out to me that a memory leak is being
00225   // created when you just call Ifpack_ILU::Compute() over and over again.
00226   // Rob H. said that he will check in a fix the the development branch when
00227   // he can.
00228   if(startingOver) {
00229     if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00230       *out << "\nCreating the initial Ifpack_Preconditioner object of type \'"<<Ifpack::toString(precType_)<<"\' ...\n";
00231     timer.start(true);
00232 #ifdef STRATIMIKOS_TEUCHOS_TIME_MONITOR
00233     Teuchos::TimeMonitor creationTimeMonitor(*creationTimer);
00234 #endif
00235     // Create the initial preconditioner
00236     ifpack_precOp = rcp(
00237       ::Ifpack::Create(
00238         precType_
00239         ,const_cast<Epetra_RowMatrix*>(&*epetraFwdRowMat)
00240         ,overlap_
00241         )
00242       );
00243     timer.stop();
00244     if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00245       OSTab(out).o() <<"=> Creation time = "<<timer.totalElapsedTime()<<" sec\n";
00246     // Set parameters if the list exists
00247     if(paramList_.get()) {
00248       Teuchos::ParameterList
00249         &ifpackSettingsPL = paramList_->sublist(IfpackSettings_name);
00250       // Above will create new sublist if it does not exist!
00251       TEUCHOS_TEST_FOR_EXCEPT(0!=ifpack_precOp->SetParameters(ifpackSettingsPL));
00252       // Above, I have not idea how any error messages for a mistake will be
00253       // reported back to the user!
00254     }
00255     // Initialize the structure for the preconditioner
00256     TEUCHOS_TEST_FOR_EXCEPT(0!=ifpack_precOp->Initialize());
00257   }
00258   //
00259   // Attach the epetraFwdOp to the ifpack_precOp to guarantee that it will not go away
00260   //
00261   set_extra_data(epetraFwdOp, "IFPF::epetraFwdOp", Teuchos::inOutArg(ifpack_precOp),
00262     Teuchos::POST_DESTROY, false);
00263   //
00264   // Update the factorization
00265   //
00266   {
00267     if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00268       *out << "\nComputing the preconditioner ...\n";
00269 #ifdef STRATIMIKOS_TEUCHOS_TIME_MONITOR
00270     Teuchos::TimeMonitor factorizationTimeMonitor(*factorizationTimer);
00271 #endif
00272     timer.start(true);
00273     TEUCHOS_TEST_FOR_EXCEPT(0!=ifpack_precOp->Compute());
00274     timer.stop();
00275     if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00276       OSTab(out).o() <<"=> Setup time = "<<timer.totalElapsedTime()<<" sec\n";
00277   }
00278   //
00279   // Compute the conditioner number estimate if asked
00280   //
00281 
00282   // ToDo: Implement
00283 
00284   //
00285   // Attach fwdOp to the ifpack_precOp
00286   //
00287   set_extra_data(fwdOpSrc, "IFPF::fwdOpSrc", Teuchos::inOutArg(ifpack_precOp),
00288     Teuchos::POST_DESTROY, false);
00289   //
00290   // Initialize the output EpetraLinearOp
00291   //
00292   if(startingOver) {
00293     epetra_precOp = rcp(new EpetraLinearOp);
00294   }
00295   epetra_precOp->initialize(
00296     ifpack_precOp
00297     ,epetraFwdOpTransp
00298     ,EPETRA_OP_APPLY_APPLY_INVERSE
00299     ,EPETRA_OP_ADJOINT_SUPPORTED
00300     );
00301   if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_MEDIUM)) {
00302     *out << "\nDescription of created preconditioner:\n";
00303     OSTab tab2(out);
00304     ifpack_precOp->Print(*out);
00305   }
00306 
00307   //
00308   // Initialize the preconditioner
00309   //
00310   defaultPrec->initializeUnspecified(
00311     Teuchos::rcp_implicit_cast<LinearOpBase<double> >(epetra_precOp)
00312     );
00313   totalTimer.stop();
00314   if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
00315     *out << "\nTotal time in IfpackPreconditionerFactory = "<<totalTimer.totalElapsedTime()<<" sec\n";
00316   if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW))
00317     *out << "\nLeaving Thyra::IfpackPreconditionerFactory::initializePrec(...) ...\n";
00318 }
00319 
00320 void IfpackPreconditionerFactory::uninitializePrec(
00321   PreconditionerBase<double>                                *prec
00322   ,Teuchos::RCP<const LinearOpSourceBase<double> >  *fwdOpSrc
00323   ,ESupportSolveUse                                         *supportSolveUse
00324   ) const
00325 {
00326   TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement when needed!
00327 }
00328 
00329 // Overridden from ParameterListAcceptor
00330 
00331 void IfpackPreconditionerFactory::setParameterList(Teuchos::RCP<Teuchos::ParameterList> const& paramList)
00332 {
00333   TEUCHOS_TEST_FOR_EXCEPT(paramList.get()==NULL);
00334   paramList->validateParameters(*this->getValidParameters(),2);
00335   // Note: The above validation will validate right down into the the sublist
00336   // named IfpackSettings_name!
00337   paramList_ = paramList;
00338   overlap_ = paramList_->get(Overlap_name,Overlap_default);
00339   std::ostringstream oss;
00340   oss << "(sub)list \""<<paramList->name()<<"\"parameter \"Prec Type\"";
00341   precType_ =
00342     ( paramList_.get()
00343       ? precTypeValidator->getIntegralValue(*paramList_,PrecType_name,PrecTypeName_default)
00344       : PrecType_default
00345       );
00346   Teuchos::readVerboseObjectSublist(&*paramList_,this);
00347 #ifdef TEUCHOS_DEBUG
00348   // Validate my use of the parameters!
00349   paramList->validateParameters(*this->getValidParameters(),1);
00350 #endif
00351 }
00352 
00353 Teuchos::RCP<Teuchos::ParameterList>
00354 IfpackPreconditionerFactory::getNonconstParameterList()
00355 {
00356   return paramList_;
00357 }
00358 
00359 Teuchos::RCP<Teuchos::ParameterList>
00360 IfpackPreconditionerFactory::unsetParameterList()
00361 {
00362   Teuchos::RCP<Teuchos::ParameterList> _paramList = paramList_;
00363   paramList_ = Teuchos::null;
00364   return _paramList;
00365 }
00366 
00367 Teuchos::RCP<const Teuchos::ParameterList>
00368 IfpackPreconditionerFactory::getParameterList() const
00369 {
00370   return paramList_;
00371 }
00372 
00373 Teuchos::RCP<const Teuchos::ParameterList>
00374 IfpackPreconditionerFactory::getValidParameters() const
00375 {
00376   using Teuchos::rcp;
00377   using Teuchos::rcp_implicit_cast;
00378   typedef Teuchos::ParameterEntryValidator PEV;
00379   static Teuchos::RCP<Teuchos::ParameterList> validParamList;
00380   if(validParamList.get()==NULL) {
00381     validParamList = Teuchos::rcp(new Teuchos::ParameterList(Ifpack_name));
00382     {
00383       // Create the validator for the preconditioner type!
00384       Teuchos::Array<std::string>
00385         precTypeNames;
00386       precTypeNames.insert(
00387         precTypeNames.begin(),
00388         &Ifpack::precTypeNames[0],
00389         &Ifpack::precTypeNames[0] + Ifpack::numPrecTypes
00390         );
00391       Teuchos::Array<Ifpack::EPrecType>
00392         precTypeValues;
00393       precTypeValues.insert(
00394         precTypeValues.begin(),
00395         &Ifpack::precTypeValues[0],
00396         &Ifpack::precTypeValues[0] + Ifpack::numPrecTypes
00397         );
00398       precTypeValidator = rcp(
00399         new Teuchos::StringToIntegralParameterEntryValidator<Ifpack::EPrecType>(
00400           precTypeNames,precTypeValues,PrecType_name
00401           )
00402         );
00403     }
00404     validParamList->set(
00405       PrecType_name, PrecTypeName_default,
00406       "Type of Ifpack preconditioner to use.",
00407       rcp_implicit_cast<const PEV>(precTypeValidator)
00408       );
00409     validParamList->set(
00410       Overlap_name, Overlap_default,
00411       "Number of rows/columns overlapped between subdomains in different"
00412       "\nprocesses in the additive Schwarz-type domain-decomposition preconditioners."
00413       );
00414     validParamList->sublist(
00415       IfpackSettings_name, false,
00416       "Preconditioner settings that are passed onto the Ifpack preconditioners themselves."
00417       ).setParameters(Ifpack_GetValidParameters());
00418     // Note that in the above setParameterList(...) function that we actually
00419     // validate down into the first level of this sublist.  Really the
00420     // Ifpack_Preconditioner objects themselves should do validation but we do
00421     // it ourselves taking the return from the Ifpack_GetValidParameters()
00422     // function as gospel!
00423     Teuchos::setupVerboseObjectSublist(&*validParamList);
00424   }
00425   return validParamList;
00426 }
00427 
00428 // Public functions overridden from Teuchos::Describable
00429 
00430 std::string IfpackPreconditionerFactory::description() const
00431 {
00432   std::ostringstream oss;
00433   oss << "Thyra::IfpackPreconditionerFactory{";
00434   oss << "precType=\"" << ::Ifpack::toString(precType_) << "\"";
00435   oss << ",overlap=" << overlap_;
00436   oss << "}";
00437   return oss.str();
00438 }
00439 
00440 // private
00441 
00442 void IfpackPreconditionerFactory::initializeTimers()
00443 {
00444   if(!overallTimer.get()) {
00445 #ifdef STRATIMIKOS_TEUCHOS_TIME_MONITOR
00446     overallTimer       = Teuchos::TimeMonitor::getNewTimer("Stratimikos: IfpackPF");
00447     creationTimer      = Teuchos::TimeMonitor::getNewTimer("Stratimikos: IfpackPF:Creation");
00448     factorizationTimer = Teuchos::TimeMonitor::getNewTimer("Stratimikos: IfpackPF:Factorization");
00449 #endif
00450   }
00451 }
00452 
00453 } // namespace Thyra
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines