1
2
3
4
5
6
7
8
9
10
11
12 #include "HypreSolver.hpp"
13 #include "HypreParMatrix.hpp"
14
15 #ifdef MOAB_HAVE_MPI
16
17 #include "hypre_parcsr.hpp"
18
19 #include <fstream>
20 #include <iostream>
21 #include <cmath>
22 #include <cstdlib>
23 #include <cassert>
24
25 using namespace std;
26
27 namespace moab
28 {
29 #define moab_hypre_assert( a, b ) \
30 { \
31 }
32 #define moab_hypre_assert_t( a, b ) \
33 { \
34 if( !a ) \
35 { \
36 std::cout << "HYPRE Error: " << b << std::endl; \
37 exit( -1 ); \
38 }
39
40 HypreSolver::HypreSolver( bool iterative ) : AbstractSolver( iterative )
41 {
42 A = NULL;
43 setup_called = 0;
44 B = X = NULL;
45 }
46
47 HypreSolver::HypreSolver( HypreParMatrix* _A, bool iterative ) : AbstractSolver( iterative )
48 {
49 A = _A;
50 setup_called = 0;
51 B = X = NULL;
52 }
53
54 HYPRE_Int HypreSolver::Solve( const HypreParVector& b, HypreParVector& x ) const
55 {
56 HYPRE_Int err;
57
58 if( A == NULL )
59 {
60 MB_SET_ERR_RET_VAL( "HypreSolver::Solve (...) : HypreParMatrix A is missing", 1 );
61 }
62
63 if( !setup_called )
64 {
65 err = SetupFcn()( *this, *A, b.x_par, x.x_par );
66 setup_called = 1;
67 }
68
69 if( !iterative_mode )
70 {
71 x = 0.0;
72 }
73
74 err = SolveFcn()( *this, *A, b.x_par, x.x_par );
75 return err;
76 }
77
78 HypreSolver::~HypreSolver()
79 {
80 if( B )
81 {
82 delete B;
83 }
84
85 if( X )
86 {
87 delete X;
88 }
89 }
90
91 HyprePCG::HyprePCG( HypreParMatrix& _A ) : HypreSolver( &_A, true )
92 {
93 iterative_mode = true;
94 HYPRE_ParCSRPCGCreate( A->GetParallelCommunicator()->comm(), &pcg_solver );
95 }
96
97 void HyprePCG::SetTol( double tol )
98 {
99 HYPRE_PCGSetTol( pcg_solver, tol );
100 }
101
102 void HyprePCG::SetMaxIter( int max_iter )
103 {
104 HYPRE_PCGSetMaxIter( pcg_solver, max_iter );
105 }
106
107 void HyprePCG::SetLogging( int logging )
108 {
109 HYPRE_PCGSetLogging( pcg_solver, logging );
110 }
111
112 void HyprePCG::Verbosity( int print_lvl )
113 {
114 HYPRE_ParCSRPCGSetPrintLevel( pcg_solver, print_lvl );
115 }
116
117 void HyprePCG::SetPreconditioner( HypreSolver& precond )
118 {
119 HYPRE_ParCSRPCGSetPrecond( pcg_solver, precond.SolveFcn(), precond.SetupFcn(), precond );
120 }
121
122 void HyprePCG::SetResidualConvergenceOptions( int res_frequency, double rtol )
123 {
124 HYPRE_PCGSetTwoNorm( pcg_solver, 1 );
125
126 if( res_frequency > 0 )
127 {
128 HYPRE_PCGSetRecomputeResidualP( pcg_solver, res_frequency );
129 }
130
131 if( rtol > 0.0 )
132 {
133 HYPRE_PCGSetResidualTol( pcg_solver, rtol );
134 }
135 }
136
137 HYPRE_Int HyprePCG::Solve( const HypreParVector& b, HypreParVector& x ) const
138 {
139 HYPRE_Int err;
140 int myid;
141 HYPRE_Int time_index = 0;
142 HYPRE_Int num_iterations;
143 double final_res_norm;
144 moab::ParallelComm* pcomm;
145 HYPRE_Int print_level;
146 HYPRE_PCGGetPrintLevel( pcg_solver, &print_level );
147 pcomm = A->GetParallelCommunicator();
148
149 if( !setup_called )
150 {
151 if( print_level > 0 )
152 {
153 #ifdef HYPRE_TIMING
154 time_index = hypre_InitializeTiming( "PCG Setup" );
155 hypre_BeginTiming( time_index );
156 #endif
157 }
158
159 err = HYPRE_ParCSRPCGSetup( pcg_solver, *A, (HYPRE_ParVector)b, (HYPRE_ParVector)x );
160 setup_called = 1;
161
162 if( err != 0 )
163 {
164 cout << "PCG Setup failed with error = " << err << endl;
165 return err;
166 }
167
168 if( print_level > 0 )
169 {
170 #ifdef HYPRE_TIMING
171 hypre_EndTiming( time_index );
172 hypre_PrintTiming( "Setup phase times", pcomm->comm() );
173 hypre_FinalizeTiming( time_index );
174 hypre_ClearTiming();
175 #endif
176 }
177 }
178
179 if( print_level > 0 )
180 {
181 #ifdef HYPRE_TIMING
182 time_index = hypre_InitializeTiming( "PCG Solve" );
183 hypre_BeginTiming( time_index );
184 #endif
185 }
186
187 if( !iterative_mode )
188 {
189 x = 0.0;
190 }
191
192 err = HYPRE_ParCSRPCGSolve( pcg_solver, *A, (HYPRE_ParVector)b, (HYPRE_ParVector)x );
193
194 if( print_level > 0 )
195 {
196 #ifdef HYPRE_TIMING
197 hypre_EndTiming( time_index );
198 hypre_PrintTiming( "Solve phase times", pcomm->comm() );
199 hypre_FinalizeTiming( time_index );
200 hypre_ClearTiming();
201 #endif
202 HYPRE_ParCSRPCGGetNumIterations( pcg_solver, &num_iterations );
203 HYPRE_ParCSRPCGGetFinalRelativeResidualNorm( pcg_solver, &final_res_norm );
204 MPI_Comm_rank( pcomm->comm(), &myid );
205
206 if( myid == 0 )
207 {
208 cout << "PCG Iterations = " << num_iterations << endl
209 << "Final PCG Relative Residual Norm = " << final_res_norm << endl;
210 }
211 }
212
213 return err;
214 }
215
216 HyprePCG::~HyprePCG()
217 {
218 HYPRE_ParCSRPCGDestroy( pcg_solver );
219 }
220
221 HypreGMRES::HypreGMRES( HypreParMatrix& _A ) : HypreSolver( &_A, true )
222 {
223 MPI_Comm comm;
224 int k_dim = 50;
225 int max_iter = 100;
226 double tol = 1e-6;
227 iterative_mode = true;
228 HYPRE_ParCSRMatrixGetComm( *A, &comm );
229 HYPRE_ParCSRGMRESCreate( comm, &gmres_solver );
230 HYPRE_ParCSRGMRESSetKDim( gmres_solver, k_dim );
231 HYPRE_ParCSRGMRESSetMaxIter( gmres_solver, max_iter );
232 HYPRE_ParCSRGMRESSetTol( gmres_solver, tol );
233 }
234
235 void HypreGMRES::SetTol( double atol, double rtol )
236 {
237 HYPRE_GMRESSetAbsoluteTol( gmres_solver, atol );
238 HYPRE_GMRESSetTol( gmres_solver, rtol );
239 }
240
241 void HypreGMRES::SetMaxIter( int max_iter )
242 {
243 HYPRE_GMRESSetMaxIter( gmres_solver, max_iter );
244 }
245
246 void HypreGMRES::SetKDim( int k_dim )
247 {
248 HYPRE_GMRESSetKDim( gmres_solver, k_dim );
249 }
250
251 void HypreGMRES::SetLogging( int logging )
252 {
253 HYPRE_GMRESSetLogging( gmres_solver, logging );
254 }
255
256 void HypreGMRES::Verbosity( int print_lvl )
257 {
258 HYPRE_GMRESSetPrintLevel( gmres_solver, print_lvl );
259 }
260
261 void HypreGMRES::SetPreconditioner( HypreSolver& precond )
262 {
263 HYPRE_ParCSRGMRESSetPrecond( gmres_solver, precond.SolveFcn(), precond.SetupFcn(), precond );
264 }
265
266 HYPRE_Int HypreGMRES::Solve( const HypreParVector& b, HypreParVector& x ) const
267 {
268 HYPRE_Int err;
269 int myid;
270 HYPRE_Int time_index = 0;
271 HYPRE_Int num_iterations;
272 double final_res_norm;
273 MPI_Comm comm;
274 HYPRE_Int print_level;
275 HYPRE_GMRESGetPrintLevel( gmres_solver, &print_level );
276 HYPRE_ParCSRMatrixGetComm( *A, &comm );
277
278 if( !setup_called )
279 {
280 if( print_level > 0 )
281 {
282 #ifdef HYPRE_TIMING
283 time_index = hypre_InitializeTiming( "GMRES Setup" );
284 hypre_BeginTiming( time_index );
285 #endif
286 }
287
288 err = HYPRE_ParCSRGMRESSetup( gmres_solver, *A, b, x );
289 setup_called = 1;
290
291 if( err != 0 )
292 {
293 cout << "PCG Setup failed with error = " << err << endl;
294 return err;
295 }
296
297 if( print_level > 0 )
298 {
299 #ifdef HYPRE_TIMING
300 hypre_EndTiming( time_index );
301 hypre_PrintTiming( "Setup phase times", comm );
302 hypre_FinalizeTiming( time_index );
303 hypre_ClearTiming();
304 #endif
305 }
306 }
307
308 if( print_level > 0 )
309 {
310 #ifdef HYPRE_TIMING
311 time_index = hypre_InitializeTiming( "GMRES Solve" );
312 hypre_BeginTiming( time_index );
313 #endif
314 }
315
316 if( !iterative_mode )
317 {
318 x = 0.0;
319 }
320
321 err = HYPRE_ParCSRGMRESSolve( gmres_solver, *A, b, x );
322
323 if( print_level > 0 )
324 {
325 #ifdef HYPRE_TIMING
326 hypre_EndTiming( time_index );
327 hypre_PrintTiming( "Solve phase times", comm );
328 hypre_FinalizeTiming( time_index );
329 hypre_ClearTiming();
330 #endif
331 HYPRE_ParCSRGMRESGetNumIterations( gmres_solver, &num_iterations );
332 HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm( gmres_solver, &final_res_norm );
333 MPI_Comm_rank( comm, &myid );
334
335 if( myid == 0 )
336 {
337 cout << "GMRES Iterations = " << num_iterations << endl
338 << "Final GMRES Relative Residual Norm = " << final_res_norm << endl;
339 }
340 }
341
342 return err;
343 }
344
345 HypreGMRES::~HypreGMRES()
346 {
347 HYPRE_ParCSRGMRESDestroy( gmres_solver );
348 }
349
350 HypreParaSails::HypreParaSails( HypreParMatrix& A ) : HypreSolver( &A )
351 {
352 MPI_Comm comm;
353 int sai_max_levels = 1;
354 double sai_threshold = 0.1;
355 double sai_filter = 0.1;
356 int sai_sym = 0;
357 double sai_loadbal = 0.0;
358 int sai_reuse = 0;
359 int sai_logging = 1;
360 HYPRE_ParCSRMatrixGetComm( A, &comm );
361 HYPRE_ParaSailsCreate( comm, &sai_precond );
362 HYPRE_ParaSailsSetParams( sai_precond, sai_threshold, sai_max_levels );
363 HYPRE_ParaSailsSetFilter( sai_precond, sai_filter );
364 HYPRE_ParaSailsSetSym( sai_precond, sai_sym );
365 HYPRE_ParaSailsSetLoadbal( sai_precond, sai_loadbal );
366 HYPRE_ParaSailsSetReuse( sai_precond, sai_reuse );
367 HYPRE_ParaSailsSetLogging( sai_precond, sai_logging );
368 }
369
370 void HypreParaSails::SetSymmetry( int sym )
371 {
372 HYPRE_ParaSailsSetSym( sai_precond, sym );
373 }
374
375 HypreParaSails::~HypreParaSails()
376 {
377 HYPRE_ParaSailsDestroy( sai_precond );
378 }
379
380 HypreBoomerAMG::HypreBoomerAMG()
381 {
382 HYPRE_BoomerAMGCreate( &amg_precond );
383 SetDefaultOptions();
384 }
385
386 HypreBoomerAMG::HypreBoomerAMG( HypreParMatrix& A ) : HypreSolver( &A )
387 {
388 HYPRE_BoomerAMGCreate( &amg_precond );
389 SetDefaultOptions();
390 }
391
392 void HypreBoomerAMG::SetDefaultOptions()
393 {
394
395 int coarsen_type = 10;
396 int agg_levels = 2;
397 double theta = 0.25;
398
399 int interp_type = 6;
400 int Pmax = 4;
401
402 int relax_type = 10;
403 int relax_sweeps = 1;
404
405 int print_level = 1;
406 int max_levels = 25;
407 HYPRE_BoomerAMGSetCoarsenType( amg_precond, coarsen_type );
408 HYPRE_BoomerAMGSetAggNumLevels( amg_precond, agg_levels );
409 HYPRE_BoomerAMGSetRelaxType( amg_precond, relax_type );
410 HYPRE_BoomerAMGSetNumSweeps( amg_precond, relax_sweeps );
411 HYPRE_BoomerAMGSetStrongThreshold( amg_precond, theta );
412 HYPRE_BoomerAMGSetInterpType( amg_precond, interp_type );
413 HYPRE_BoomerAMGSetPMaxElmts( amg_precond, Pmax );
414 HYPRE_BoomerAMGSetPrintLevel( amg_precond, print_level );
415 HYPRE_BoomerAMGSetMaxLevels( amg_precond, max_levels );
416
417 HYPRE_BoomerAMGSetMaxIter( amg_precond, 1 );
418 HYPRE_BoomerAMGSetTol( amg_precond, 0.0 );
419 }
420
421 void HypreBoomerAMG::ResetAMGPrecond()
422 {
423 HYPRE_Int coarsen_type;
424 HYPRE_Int agg_levels;
425 HYPRE_Int relax_type;
426 HYPRE_Int relax_sweeps;
427 HYPRE_Real theta;
428 HYPRE_Int interp_type;
429 HYPRE_Int Pmax;
430 HYPRE_Int print_level;
431 HYPRE_Int dim;
432 hypre_ParAMGData* amg_data = (hypre_ParAMGData*)amg_precond;
433
434 HYPRE_BoomerAMGGetCoarsenType( amg_precond, &coarsen_type );
435 agg_levels = hypre_ParAMGDataAggNumLevels( amg_data );
436 relax_type = hypre_ParAMGDataUserRelaxType( amg_data );
437 relax_sweeps = hypre_ParAMGDataUserNumSweeps( amg_data );
438 HYPRE_BoomerAMGGetStrongThreshold( amg_precond, &theta );
439 hypre_BoomerAMGGetInterpType( amg_precond, &interp_type );
440 HYPRE_BoomerAMGGetPMaxElmts( amg_precond, &Pmax );
441 HYPRE_BoomerAMGGetPrintLevel( amg_precond, &print_level );
442 HYPRE_BoomerAMGGetNumFunctions( amg_precond, &dim );
443 HYPRE_BoomerAMGDestroy( amg_precond );
444 HYPRE_BoomerAMGCreate( &amg_precond );
445 HYPRE_BoomerAMGSetCoarsenType( amg_precond, coarsen_type );
446 HYPRE_BoomerAMGSetAggNumLevels( amg_precond, agg_levels );
447 HYPRE_BoomerAMGSetRelaxType( amg_precond, relax_type );
448 HYPRE_BoomerAMGSetNumSweeps( amg_precond, relax_sweeps );
449 HYPRE_BoomerAMGSetMaxLevels( amg_precond, 25 );
450 HYPRE_BoomerAMGSetTol( amg_precond, 0.0 );
451 HYPRE_BoomerAMGSetMaxIter( amg_precond, 1 );
452 HYPRE_BoomerAMGSetStrongThreshold( amg_precond, theta );
453 HYPRE_BoomerAMGSetInterpType( amg_precond, interp_type );
454 HYPRE_BoomerAMGSetPMaxElmts( amg_precond, Pmax );
455 HYPRE_BoomerAMGSetPrintLevel( amg_precond, print_level );
456 HYPRE_BoomerAMGSetNumFunctions( amg_precond, dim );
457 }
458
459 void HypreBoomerAMG::SetOperator( const HypreParMatrix& op )
460 {
461 if( A )
462 {
463 ResetAMGPrecond();
464 }
465
466
467 A = const_cast< HypreParMatrix* >( &op );
468 setup_called = 0;
469 delete X;
470 delete B;
471 B = X = NULL;
472 }
473
474 void HypreBoomerAMG::SetSystemsOptions( int dim )
475 {
476 HYPRE_BoomerAMGSetNumFunctions( amg_precond, dim );
477
478 HYPRE_BoomerAMGSetAggNumLevels( amg_precond, 0 );
479 HYPRE_BoomerAMGSetStrongThreshold( amg_precond, dim * 0.25 );
480 }
481
482 HypreBoomerAMG::~HypreBoomerAMG()
483 {
484 HYPRE_BoomerAMGDestroy( amg_precond );
485 }
486
487 }
488
489 #endif