PlayaAztecSolver.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                 Playa: Programmable Linear Algebra
00005 //                 Copyright 2012 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
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 Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
00041 
00042 
00043 #include "PlayaAztecSolver.hpp"
00044 #include "PlayaEpetraVector.hpp"
00045 #include "PlayaEpetraMatrix.hpp"
00046 #include "Ifpack_Preconditioner.h"
00047 #include "Ifpack.h"
00048 #include "EpetraPlayaOperator.hpp"
00049 #include "Teuchos_basic_oblackholestream.hpp"
00050 
00051 
00052 
00053 #ifndef HAVE_TEUCHOS_EXPLICIT_INSTANTIATION
00054 #include "PlayaVectorImpl.hpp"
00055 #include "PlayaLinearOperatorImpl.hpp"
00056 #include "PlayaLinearSolverImpl.hpp"
00057 #endif
00058 
00059 #ifdef HAVE_ML
00060 #include "ml_include.h"
00061 #include "ml_epetra_utils.h"
00062 #include "ml_epetra_operator.h"
00063 #include "ml_aztec_utils.h"
00064 #include "ml_MultiLevelPreconditioner.h"
00065 using namespace ML_Epetra;
00066 #else
00067 #error blarf
00068 #endif
00069 
00070 using namespace Playa;
00071 using namespace Teuchos;
00072 
00073 
00074 AztecSolver::AztecSolver(const ParameterList& params)
00075   : LinearSolverBase<double>(params),
00076     options_(AZ_OPTIONS_SIZE),
00077     parameters_(AZ_PARAMS_SIZE),
00078     useML_(false),
00079     useIfpack_(false),
00080     useUserPrec_(false),
00081     aztec_recursive_iterate_(false),
00082     precParams_(),
00083     userPrec_(),
00084     aztec_status(AZ_STATUS_SIZE),
00085     aztec_proc_config(AZ_PROC_SIZE)
00086 {
00087   initParamMap();
00088 
00089   /* initialize the options and parameters with Aztec's defaults */
00090   AZ_defaults((int*) &(options_[0]), (double*) &(parameters_[0]));
00091 
00092 
00093   /* Set options according to the parameter list */
00094   ParameterList::ConstIterator iter;
00095   for (iter=params.begin(); iter != params.end(); ++iter)
00096   {
00097     const std::string& name = params.name(iter);
00098     const ParameterEntry& entry = params.entry(iter);
00099 
00100     if (entry.isList())
00101     {
00102       if (name=="Preconditioner")
00103       {
00104         precParams_ = params.sublist("Preconditioner");
00105         TEUCHOS_TEST_FOR_EXCEPTION(!precParams_.isParameter("Type"), std::runtime_error,
00106           "preconditioner type not specified in parameter list "
00107           << precParams_);
00108         if (precParams_.get<string>("Type") == "ML")
00109         {
00110           useML_ = true;
00111         }
00112         else if (precParams_.get<string>("Type") == "Ifpack")
00113         {
00114           useIfpack_ = true;
00115         }
00116         else if (precParams_.get<string>("Type") == "User")
00117         {
00118           useUserPrec_ = true;
00119         }
00120         continue;
00121       }
00122     }
00123 
00124     /* Check that the param name appears in the table of Aztec params */
00125     if (paramMap().find(name) == paramMap().end()) continue;
00126 
00127     /* find the integer ID used by Aztec to identify this parameter */
00128     int aztecCode = paramMap()[name];
00129 
00130     if (name=="Recursive Iterate")
00131     {
00132       if (getValue<int>(entry))
00133         aztec_recursive_iterate_ = true;
00134       else
00135         aztec_recursive_iterate_ = false;
00136       continue;
00137     }
00138 
00139 
00140     /* We now need to figure out what to do with the value of the
00141      * parameter. If it is a std::string, then it corresponds to a
00142      * predefined Aztec option value. If it is an integer, then
00143      * it is the numerical setting for an Aztec option. If it is
00144      * a double, then it is the numerical setting for an Aztec
00145      * parameter. */
00146     if (entry.isType<string>())
00147     {
00148       std::string val = getValue<string>(entry);
00149       TEUCHOS_TEST_FOR_EXCEPTION(paramMap().find(val) == paramMap().end(),
00150         std::runtime_error,
00151         "Aztec solver ctor: [" << val << "] is not a "
00152         "valid Aztec option value");
00153       int optionVal = paramMap()[val];
00154       options_[aztecCode] = optionVal;
00155     }
00156     else if (entry.isType<int>())
00157     {
00158       int val = getValue<int>(entry);
00159       options_[aztecCode] = val;
00160       if (name=="Verbosity") setVerb(val);
00161     }
00162     else if (entry.isType<double>())
00163     {
00164       double val = getValue<double>(entry);
00165       parameters_[aztecCode] = val;
00166     }
00167   }
00168 }
00169 
00170 
00171 AztecSolver::AztecSolver(const Teuchos::map<int, int>& aztecOptions,
00172   const Teuchos::map<int, double>& aztecParameters)
00173   : LinearSolverBase<double>(ParameterList()),
00174     options_(AZ_OPTIONS_SIZE),
00175     parameters_(AZ_PARAMS_SIZE),
00176     useML_(false),
00177     useIfpack_(false),
00178     useUserPrec_(false),
00179     aztec_recursive_iterate_(false),
00180     precParams_(),
00181     userPrec_(),
00182     aztec_status(AZ_STATUS_SIZE),
00183     aztec_proc_config(AZ_PROC_SIZE)
00184 {
00185   if (aztecOptions.find(AZ_recursive_iterate) != aztecOptions.end())
00186   {
00187     aztec_recursive_iterate_ = true;
00188   }
00189 
00190   /* initialize the options and parameters with Aztec's defaults */
00191   AZ_defaults((int*) &(options_[0]), (double*) &(parameters_[0]));
00192 
00193   /* set user-specified options  */
00194   map<int, int>::const_iterator opIter;
00195   for (opIter=aztecOptions.begin(); opIter!=aztecOptions.end(); opIter++)
00196   {
00197     int opKey = opIter->first;
00198     if (opKey==AZ_recursive_iterate) continue;
00199     int opValue = opIter->second;
00200     options_[opKey] = opValue;
00201   }
00202 
00203   /* set user-specified params  */
00204   map<int, double>::const_iterator parIter;
00205   for (parIter=aztecParameters.begin(); parIter!=aztecParameters.end();
00206        parIter++)
00207   {
00208     int parKey = parIter->first;
00209     double parValue = parIter->second;
00210     parameters_[parKey] = parValue;
00211   }
00212 }
00213 
00214 
00215 void AztecSolver::updateTolerance(const double& tol)
00216 {
00217   parameters_[AZ_tol] = tol;
00218 }
00219 
00220 SolverState<double> AztecSolver::solve(const LinearOperator<double>& op, 
00221   const Vector<double>& rhs, 
00222   Vector<double>& soln) const
00223 {
00224   RCP<ostream> out;
00225   if (verb()==0)
00226   {
00227     out = rcp(new oblackholestream());
00228   }
00229   else
00230   {
00231     out = rcp(&Out::os(), false);
00232   }
00233   RCP<MultiLevelPreconditioner> mlPrec;
00234   RCP<Ifpack_Preconditioner> ifpackPrec;
00235   RCP<Epetra_Operator> prec;
00236 
00237   Playa::Vector<double> bCopy = rhs.copy();
00238   Playa::Vector<double> xCopy = rhs.copy();
00239 
00240   if (verb() > 4) 
00241   {
00242     *out << "rhs=" << bCopy << std::endl;
00243   }
00244 
00245   Epetra_Vector* b = EpetraVector::getConcretePtr(bCopy);
00246   Epetra_Vector* x = EpetraVector::getConcretePtr(xCopy);
00247 
00248   Epetra_CrsMatrix& A = EpetraMatrix::getConcrete(op);
00249 
00250   AztecOO aztec(&A, x, b);
00251 
00252   aztec.SetAllAztecOptions((int*) &(options_[0]));
00253   aztec.SetAllAztecParams((double*) &(parameters_[0]));
00254   aztec.SetOutputStream(*out);
00255   aztec.SetErrorStream(*out);
00256   
00257   int maxIters = options_[AZ_max_iter];
00258   double tol = parameters_[AZ_tol];
00259 
00260   if (useML_)
00261   {
00262     std::string precType = precParams_.get<string>("Problem Type");
00263     ParameterList mlParams;
00264     ML_Epetra::SetDefaults(precType, mlParams);
00265     //#ifndef TRILINOS_6
00266     //      mlParams.setParameters(precParams_.sublist("ML Settings"));
00267     //#else
00268     ParameterList::ConstIterator iter;
00269     ParameterList mlSettings = precParams_.sublist("ML Settings");
00270     for (iter=mlSettings.begin(); iter!=mlSettings.end(); ++iter)
00271     {
00272       const std::string& name = mlSettings.name(iter);
00273       const ParameterEntry& entry = mlSettings.entry(iter);
00274       mlParams.setEntry(name, entry);
00275     }
00276     //#endif
00277     mlPrec = rcp(new ML_Epetra::MultiLevelPreconditioner(A, mlParams));
00278     prec = rcp_dynamic_cast<Epetra_Operator>(mlPrec);
00279   }
00280   else if (useIfpack_)
00281   {
00282     Ifpack precFactory;
00283     int overlap = precParams_.get<int>("Overlap");
00284     std::string precType = precParams_.get<string>("Prec Type");
00285 
00286     ParameterList ifpackParams = precParams_.sublist("Ifpack Settings");
00287 
00288     ifpackPrec = rcp(precFactory.Create(precType, &A, overlap));
00289     prec = rcp_dynamic_cast<Epetra_Operator>(ifpackPrec);
00290     ifpackPrec->SetParameters(ifpackParams);
00291     ifpackPrec->Initialize();
00292     ifpackPrec->Compute();
00293   }
00294   else if (useUserPrec_)
00295   {
00296     TEUCHOS_TEST_FOR_EXCEPT(userPrec_.get() == 0);
00297     prec = userPrec_;
00298   }
00299   
00300   
00301   if (prec.get() != 0) aztec.SetPrecOperator(prec.get());  
00302   
00303   aztec.CheckInput();
00304   
00305   /* VEH/RST Parameter to check if we are calling aztec recursively.
00306    * If so, need to set parameter aztec_recursive_iterate to true. */
00307   if (aztec_recursive_iterate_)
00308   {
00309     aztec.recursiveIterate(maxIters, tol);
00310   }
00311   else
00312   {
00313     aztec.Iterate(maxIters, tol);
00314   }
00315   
00316   soln = xCopy;
00317 
00318   const double* status = aztec.GetAztecStatus();
00319   SolverStatusCode state = SolveCrashed;
00320 
00321   std::string msg;
00322   switch((int) status[AZ_why])
00323   {
00324     case AZ_normal:
00325       state = SolveConverged;
00326       msg = "converged";
00327       break;
00328     case AZ_param:
00329       state = SolveCrashed;
00330       msg = "failed: parameter not available";
00331       break;
00332     case AZ_breakdown:
00333       state = SolveCrashed;
00334       msg = "failed: numerical breakdown";
00335       break;
00336     case AZ_loss:
00337       state = SolveCrashed;
00338       msg = "failed: numerical loss of precision";
00339       break;
00340     case AZ_ill_cond:
00341       state = SolveCrashed;
00342       msg = "failed: ill-conditioned Hessenberg matrix in GMRES";
00343       break;
00344     case AZ_maxits:
00345       state = SolveFailedToConverge;
00346       msg = "failed: maxiters reached without converged";
00347       break;
00348   }
00349   SolverState<double> rtn(state, "Aztec solver " + msg, (int) status[AZ_its],
00350     status[AZ_r]);
00351   return rtn;
00352 }
00353 
00354 
00355 void AztecSolver::setUserPrec(const LinearOperator<double>& P,
00356   const LinearSolver<double>& pSolver)
00357 {
00358   if (useUserPrec_)
00359   {
00360     userPrec_ = rcp(new Epetra::Epetra_PlayaOperator(P, pSolver));
00361   }
00362   else
00363   {
00364     TEUCHOS_TEST_FOR_EXCEPTION(!useUserPrec_, std::runtime_error,
00365       "Attempt to set user-defined preconditioner "
00366       "after another preconditioner has been specified");
00367   }
00368 }
00369 
00370 void AztecSolver::initParamMap()
00371 {
00372   static bool first = true;
00373   if (first)
00374   {
00375     paramMap()["Method"]=AZ_solver;
00376     paramMap()["CG"]=AZ_cg;
00377     paramMap()["GMRES"]=AZ_gmres;
00378     paramMap()["CGS"]=AZ_cgs;
00379     paramMap()["TFQMR"]=AZ_tfqmr;
00380     paramMap()["BICGSTAB"]=AZ_bicgstab;
00381     paramMap()["Direct"]=AZ_lu;
00382     paramMap()["Precond"]=AZ_precond;
00383     paramMap()["None"]=AZ_none;
00384     paramMap()["Jacobi"]=AZ_Jacobi;
00385     paramMap()["Neumann Series"]=AZ_Neumann;
00386     paramMap()["Symmetric Gauss-Seidel"]=AZ_sym_GS;
00387     paramMap()["Least-Squares Polynomial"]=AZ_ls;
00388     paramMap()["Recursive Iterate"]=AZ_recursive_iterate;
00389     paramMap()["Domain Decomposition"]=AZ_dom_decomp;
00390     paramMap()["Subdomain Solver"]=AZ_subdomain_solve;
00391     paramMap()["Approximate Sparse LU"]=AZ_lu;
00392     paramMap()["Saad ILUT"]=AZ_ilut;
00393     paramMap()["ILU"]=AZ_ilu;
00394     paramMap()["RILU"]=AZ_rilu;
00395     paramMap()["Block ILU"]=AZ_bilu;
00396     paramMap()["Incomplete Cholesky"]=AZ_icc;
00397     paramMap()["Residual Scaling"]=AZ_conv;
00398     paramMap()["Initial"]=AZ_r0;
00399     paramMap()["RHS"]=AZ_rhs;
00400     paramMap()["Matrix"]=AZ_Anorm;
00401     paramMap()["Solution"]=AZ_sol;
00402     paramMap()["No Scaling"]=AZ_noscaled;
00403     paramMap()["Verbosity"]=AZ_output;
00404     paramMap()["All"]=AZ_all;
00405     paramMap()["Silent"]=AZ_none;
00406     paramMap()["Warnings"]=AZ_warnings;
00407     paramMap()["Final Residual"]=AZ_last;
00408     paramMap()["Graph Fill"]=AZ_graph_fill;
00409     paramMap()["Max Iterations"]=AZ_max_iter;
00410     paramMap()["Polynomial Order"]=AZ_poly_ord;
00411     paramMap()["Overlap"]=AZ_overlap;
00412     paramMap()["Overlap Type"]=AZ_type_overlap;
00413     paramMap()["Standard"]=AZ_standard;
00414     paramMap()["Symmetric"]=AZ_symmetric;
00415     paramMap()["Restart Size"]=AZ_kspace;
00416     paramMap()["Reorder ILU"]=AZ_reorder;
00417     paramMap()["Keep Factorization"]=AZ_keep_info;
00418     paramMap()["GMRES Orthogonalization"]=AZ_orthog;
00419     paramMap()["Classical Gram-Schmidt"]=AZ_classic;
00420     paramMap()["Modified Gram-Schmidt"]=AZ_modified;
00421     paramMap()["Auxiliary Vector"]=AZ_aux_vec;
00422     paramMap()["Residual"]=AZ_resid;
00423     paramMap()["Random"]=AZ_rand;
00424     paramMap()["Tolerance"]=AZ_tol;
00425     paramMap()["Drop Tolerance"]=AZ_drop;
00426     paramMap()["Fill Ratio"]=AZ_ilut_fill;
00427     paramMap()["Damping"]=AZ_omega;
00428 
00429     first = false;
00430   }
00431 }
00432 
00433 

Site Contact