1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 3 // reserved. See file COPYRIGHT for details. 4 // 5 // This file is part of the MFEM library. For more information and source code 6 // availability see http://mfem.org. 7 // 8 // MFEM is free software; you can redistribute it and/or modify it under the 9 // terms of the GNU Lesser General Public License (as published by the Free 10 // Software Foundation) version 2.1 dated February 1999. 11 12 /// This HYPRE library interface has been taken originally from MFEM and modified 13 /// to suit the needs for the MOAB library. 14 /// Modified by: Vijay Mahadevan 15 16 #ifndef MOAB_HYPRESOLVER 17 #define MOAB_HYPRESOLVER 18 19 #include "moab/MOABConfig.h" 20 #include "moab/Core.hpp" 21 22 #ifdef MOAB_HAVE_MPI 23 #include <mpi.h> 24 25 // Enable internal hypre timing routines 26 #ifndef HYPRE_TIMING 27 #define HYPRE_TIMING 28 #endif 29 30 #include "HypreParVector.hpp" 31 #include "HypreParMatrix.hpp" 32 33 namespace moab 34 { 35 36 /// Base class for solvers 37 class AbstractSolver 38 { 39 protected: 40 const Eigen::SparseMatrix<double> *m_operator; 41 42 public: 43 /// If true, use the second argument of Mult as an initial guess 44 bool iterative_mode; 45 46 /// Initialize a Solver AbstractSolver(bool iter_mode)47 explicit AbstractSolver(bool iter_mode) 48 { iterative_mode = iter_mode; } 49 50 /// Set/update the solver for the given operator 51 virtual void SetOperator(const HypreParMatrix &op) = 0; 52 }; 53 54 55 56 /// Abstract class for hypre's solvers and preconditioners 57 class HypreSolver : public AbstractSolver 58 { 59 public: 60 typedef HypreParVector Vector; 61 62 protected: 63 /// The linear system matrix 64 HypreParMatrix *A; 65 66 /// Right-hand side and solution vector 67 mutable HypreParVector *B, *X; 68 69 /// Was hypre's Setup function called already? 70 mutable int setup_called; 71 72 public: 73 HypreSolver(bool iterative = true); 74 75 HypreSolver(HypreParMatrix *_A, bool iterative = true); 76 77 /// Typecast to HYPRE_Solver -- return the solver 78 virtual operator HYPRE_Solver() const = 0; 79 Verbosity(int)80 virtual void Verbosity(int /*print_level*/) 81 { /* nothing to do */ } 82 83 /// Set the hypre solver to be used as a preconditioner SetPreconditioner(HypreSolver &)84 virtual void SetPreconditioner(HypreSolver &/*precond*/) 85 { /* Nothing to do */ } 86 87 /// hypre's internal Setup function 88 virtual HYPRE_PtrToParSolverFcn SetupFcn() const = 0; 89 /// hypre's internal Solve function 90 virtual HYPRE_PtrToParSolverFcn SolveFcn() const = 0; 91 SetOperator(const HypreParMatrix &)92 virtual void SetOperator(const HypreParMatrix &/*op*/) 93 { MB_SET_ERR_RET("HypreSolvers do not support SetOperator!"); } 94 95 virtual void GetFinalResidualNorm(double &normr) = 0; 96 97 virtual void GetNumIterations(int &num_iterations) = 0; 98 99 /// Solve the linear system Ax=b 100 virtual HYPRE_Int Solve(const HypreParVector &b, HypreParVector &x) const; 101 102 virtual ~HypreSolver(); 103 }; 104 105 /// PCG solver in hypre 106 class HyprePCG : public HypreSolver 107 { 108 private: 109 HYPRE_Solver pcg_solver; 110 111 public: 112 HyprePCG(HypreParMatrix &_A); 113 114 void SetTol(double tol); 115 void SetMaxIter(int max_iter); 116 void SetLogging(int logging); 117 virtual void Verbosity(int print_lvl); 118 119 /// Set the hypre solver to be used as a preconditioner 120 virtual void SetPreconditioner(HypreSolver &precond); 121 122 /** Use the L2 norm of the residual for measuring PCG convergence, plus 123 (optionally) 1) periodically recompute true residuals from scratch; and 124 2) enable residual-based stopping criteria. */ 125 void SetResidualConvergenceOptions(int res_frequency = -1, double rtol = 0.0); 126 127 /// non-hypre setting SetZeroInintialIterate()128 void SetZeroInintialIterate() { iterative_mode = false; } 129 GetFinalResidualNorm(double & normr)130 virtual void GetFinalResidualNorm(double &normr) 131 { 132 HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(pcg_solver, 133 &normr); 134 } 135 GetNumIterations(int & num_iterations)136 virtual void GetNumIterations(int &num_iterations) 137 { 138 HYPRE_Int num_it; 139 HYPRE_ParCSRPCGGetNumIterations(pcg_solver, &num_it); 140 num_iterations = internal::to_int(num_it); 141 } 142 143 /// The typecast to HYPRE_Solver returns the internal pcg_solver operator HYPRE_Solver() const144 virtual operator HYPRE_Solver() const { return pcg_solver; } 145 146 /// PCG Setup function SetupFcn() const147 virtual HYPRE_PtrToParSolverFcn SetupFcn() const 148 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRPCGSetup; } 149 /// PCG Solve function SolveFcn() const150 virtual HYPRE_PtrToParSolverFcn SolveFcn() const 151 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRPCGSolve; } 152 153 /// Solve Ax=b with hypre's PCG 154 virtual HYPRE_Int Solve(const HypreParVector &b, HypreParVector &x) const; 155 using HypreSolver::Solve; 156 157 virtual ~HyprePCG(); 158 }; 159 160 /// GMRES solver in hypre 161 class HypreGMRES : public HypreSolver 162 { 163 private: 164 HYPRE_Solver gmres_solver; 165 166 public: 167 HypreGMRES(HypreParMatrix &_A); 168 169 void SetTol(double atol, double rtol = 1e-20); 170 void SetMaxIter(int max_iter); 171 void SetKDim(int dim); 172 void SetLogging(int logging); 173 virtual void Verbosity(int print_lvl); 174 175 /// Set the hypre solver to be used as a preconditioner 176 virtual void SetPreconditioner(HypreSolver &precond); 177 178 /** Use the L2 norm of the residual for measuring PCG convergence, plus 179 (optionally) 1) periodically recompute true residuals from scratch; and 180 2) enable residual-based stopping criteria. */ SkipRealResidualCheck()181 void SkipRealResidualCheck() 182 { 183 HYPRE_GMRESSetSkipRealResidualCheck(gmres_solver, 1); 184 } 185 186 /// non-hypre setting SetZeroInintialIterate()187 void SetZeroInintialIterate() { iterative_mode = false; } 188 GetFinalResidualNorm(double & normr)189 virtual void GetFinalResidualNorm(double &normr) 190 { 191 HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(gmres_solver, 192 &normr); 193 } 194 GetNumIterations(int & num_iterations)195 virtual void GetNumIterations(int &num_iterations) 196 { 197 HYPRE_Int num_it; 198 HYPRE_GMRESGetNumIterations(gmres_solver, &num_it); 199 num_iterations = internal::to_int(num_it); 200 } 201 202 /// The typecast to HYPRE_Solver returns the internal gmres_solver operator HYPRE_Solver() const203 virtual operator HYPRE_Solver() const { return gmres_solver; } 204 205 /// GMRES Setup function SetupFcn() const206 virtual HYPRE_PtrToParSolverFcn SetupFcn() const 207 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRGMRESSetup; } 208 /// GMRES Solve function SolveFcn() const209 virtual HYPRE_PtrToParSolverFcn SolveFcn() const 210 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRGMRESSolve; } 211 212 /// Solve Ax=b with hypre's GMRES 213 virtual HYPRE_Int Solve(const HypreParVector &b, HypreParVector &x) const; 214 using HypreSolver::Solve; 215 216 virtual ~HypreGMRES(); 217 }; 218 219 /// The identity operator as a hypre solver 220 class HypreIdentity : public HypreSolver 221 { 222 public: operator HYPRE_Solver() const223 virtual operator HYPRE_Solver() const { return NULL; } 224 SetupFcn() const225 virtual HYPRE_PtrToParSolverFcn SetupFcn() const 226 { return (HYPRE_PtrToParSolverFcn) hypre_ParKrylovIdentitySetup; } SolveFcn() const227 virtual HYPRE_PtrToParSolverFcn SolveFcn() const 228 { return (HYPRE_PtrToParSolverFcn) hypre_ParKrylovIdentity; } 229 GetNumIterations(int & num_iterations)230 virtual void GetNumIterations(int &num_iterations) 231 { num_iterations = 1; } 232 GetFinalResidualNorm(double & normr)233 virtual void GetFinalResidualNorm(double &normr) 234 { normr = 0.0; } 235 ~HypreIdentity()236 virtual ~HypreIdentity() { } 237 }; 238 239 /// Jacobi preconditioner in hypre 240 class HypreDiagScale : public HypreSolver 241 { 242 public: HypreDiagScale()243 HypreDiagScale() : HypreSolver() { } HypreDiagScale(HypreParMatrix & A)244 explicit HypreDiagScale(HypreParMatrix &A) : HypreSolver(&A) { } operator HYPRE_Solver() const245 virtual operator HYPRE_Solver() const { return NULL; } 246 SetupFcn() const247 virtual HYPRE_PtrToParSolverFcn SetupFcn() const 248 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRDiagScaleSetup; } SolveFcn() const249 virtual HYPRE_PtrToParSolverFcn SolveFcn() const 250 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRDiagScale; } 251 GetNumIterations(int & num_iterations)252 virtual void GetNumIterations(int &num_iterations) 253 { num_iterations = 1; } 254 GetFinalResidualNorm(double & normr)255 virtual void GetFinalResidualNorm(double &normr) 256 { normr = 0.0; } 257 GetData()258 HypreParMatrix *GetData() { return A; } ~HypreDiagScale()259 virtual ~HypreDiagScale() { } 260 }; 261 262 263 /// The ParaSails preconditioner in hypre 264 class HypreParaSails : public HypreSolver 265 { 266 private: 267 HYPRE_Solver sai_precond; 268 269 public: 270 HypreParaSails(HypreParMatrix &A); 271 272 void SetSymmetry(int sym); 273 GetNumIterations(int & num_iterations)274 virtual void GetNumIterations(int &num_iterations) 275 { num_iterations = 1; } 276 GetFinalResidualNorm(double & normr)277 virtual void GetFinalResidualNorm(double &normr) 278 { normr = 0.0; } 279 280 /// The typecast to HYPRE_Solver returns the internal sai_precond operator HYPRE_Solver() const281 virtual operator HYPRE_Solver() const { return sai_precond; } 282 SetupFcn() const283 virtual HYPRE_PtrToParSolverFcn SetupFcn() const 284 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParaSailsSetup; } SolveFcn() const285 virtual HYPRE_PtrToParSolverFcn SolveFcn() const 286 { return (HYPRE_PtrToParSolverFcn) HYPRE_ParaSailsSolve; } 287 288 virtual ~HypreParaSails(); 289 }; 290 291 292 /// The BoomerAMG solver in hypre 293 class HypreBoomerAMG : public HypreSolver 294 { 295 private: 296 HYPRE_Solver amg_precond; 297 298 /// Default, generally robust, BoomerAMG options 299 void SetDefaultOptions(); 300 301 // If amg_precond is NULL, allocates it and sets default options. 302 // Otherwise saves the options from amg_precond, destroys it, allocates a new 303 // one, and sets its options to the saved values. 304 void ResetAMGPrecond(); 305 306 public: 307 HypreBoomerAMG(); 308 309 HypreBoomerAMG(HypreParMatrix &A); 310 311 virtual void SetOperator(const HypreParMatrix &op); 312 GetNumIterations(int & num_iterations)313 virtual void GetNumIterations(int &num_iterations) 314 { num_iterations = 1; } 315 GetFinalResidualNorm(double & normr)316 virtual void GetFinalResidualNorm(double &normr) 317 { normr = 0.0; } 318 319 /** More robust options for systems, such as elasticity. Note that BoomerAMG 320 assumes Ordering::byVDIM in the finite element space used to generate the 321 matrix A. */ 322 void SetSystemsOptions(int dim); 323 Verbosity(int print_level)324 virtual void Verbosity(int print_level) 325 { HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level); } 326 327 /// The typecast to HYPRE_Solver returns the internal amg_precond operator HYPRE_Solver() const328 virtual operator HYPRE_Solver() const { return amg_precond; } 329 SetupFcn() const330 virtual HYPRE_PtrToParSolverFcn SetupFcn() const 331 { return (HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSetup; } SolveFcn() const332 virtual HYPRE_PtrToParSolverFcn SolveFcn() const 333 { return (HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSolve; } 334 335 virtual ~HypreBoomerAMG(); 336 }; 337 338 } 339 340 #endif // MOAB_HAVE_MPI 341 342 #endif 343