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