MOAB: Mesh Oriented datABase  (version 5.5.0)
hypre_test.cpp
Go to the documentation of this file.
1 // Parts of this test have been taken from MFEM and HPCG benchmark example
2 
3 #include "moab/Core.hpp"
4 #include "HypreSolver.hpp"
5 
6 #include <iostream>
7 using namespace std;
8 
9 #undef DEBUG
10 
12  int ny,
13  int nz,
14  moab::HypreParMatrix& A,
15  moab::HypreParVector& sol,
16  moab::HypreParVector& rhs,
17  moab::HypreParVector& exactsol );
18 
19 int main( int argc, char* argv[] )
20 {
21  // double norm, d;
22  int ierr = 0;
23  double times[5];
24  int nx = 5, ny = 5, nz = 5;
25 #ifdef MOAB_HAVE_MPI
26  MPI_Init( &argc, &argv );
27  int size, rank; // Number of MPI processes, My process ID
28  MPI_Comm_size( MPI_COMM_WORLD, &size );
29  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
30 #else
31  int size = 1; // Serial case (not using MPI)
32  int rank = 0;
33 #endif
34  MPI_Comm comm = MPI_COMM_WORLD;
35 
36  moab::Core mbCore;
37  moab::Interface& mb = mbCore;
38 
39  // rval = mb.load_file(example.c_str(), &euler_set, opts.c_str());
40 
41  moab::ParallelComm* pcomm = new moab::ParallelComm( &mb, comm );
42 
43  moab::HypreParMatrix A( pcomm );
44  moab::HypreParVector x( pcomm ), b( pcomm ), xexact( pcomm );
45 #ifdef DEBUG
46 
47  if( rank == 0 )
48  {
49  int junk = 0;
50  cout << "Press enter to continue" << endl;
51  cin >> junk;
52  }
53 
54  MPI_Barrier( MPI_COMM_WORLD );
55 #endif
56 
57  if( argc > 4 )
58  {
59  if( rank == 0 )
60  cerr << "Usage:" << endl
61  << "\t" << argv[0] << " nx ny nz" << endl
62  << " where nx, ny and nz are the local sub-block dimensions, or" << endl;
63 
64  exit( 1 );
65  }
66  else
67  {
68  if( rank == 0 )
69  cout << "Using command:"
70  << "\t" << argv[0] << " nx ny nz" << endl;
71  }
72 
73  times[0] = MPI_Wtime(); // Initialize it (if needed)
74 
75  if( argc == 4 )
76  {
77  nx = atoi( argv[1] );
78  ny = atoi( argv[2] );
79  nz = atoi( argv[3] );
80  }
81 
82  GenerateTestMatrixAndVectors( nx, ny, nz, A, x, b, xexact );
83 
84  times[1] = MPI_Wtime() - times[0]; // operator creation time
85  const bool useCG = true; // TODO make into command line option
86  const bool useAMG = false; // TODO make into command line option
87  int niters = 0;
88  double normr = 0;
89  int max_iter = 150;
90  double tolerance = 1e-15; // Set tolerance to zero to make all runs do max_iter iterations
91  times[2] = MPI_Wtime(); // reset
92  moab::HypreSolver *lsSolver, *psSolver;
93 
94  if( useCG )
95  {
96  lsSolver = new moab::HyprePCG( A );
97  moab::HyprePCG* cgSolver = dynamic_cast< moab::HyprePCG* >( lsSolver );
98  cgSolver->SetTol( tolerance );
99  cgSolver->SetMaxIter( max_iter );
100  cgSolver->SetLogging( 1 );
101  cgSolver->Verbosity( 1 );
102  cgSolver->SetResidualConvergenceOptions( 3, 0.0 );
103  }
104  else
105  {
106  lsSolver = new moab::HypreGMRES( A );
107  moab::HypreGMRES* gmresSolver = dynamic_cast< moab::HypreGMRES* >( lsSolver );
108  gmresSolver->SetTol( tolerance, normr );
109  gmresSolver->SetMaxIter( max_iter );
110  gmresSolver->SetLogging( 1 );
111  gmresSolver->Verbosity( 5 );
112  gmresSolver->SetKDim( 30 );
113  }
114 
115  if( useAMG )
116  {
117  psSolver = new moab::HypreBoomerAMG( A );
118  dynamic_cast< moab::HypreBoomerAMG* >( psSolver )->SetSystemsOptions( 3 );
119  }
120  else
121  {
122  psSolver = new moab::HypreParaSails( A );
123  dynamic_cast< moab::HypreParaSails* >( psSolver )->SetSymmetry( 1 );
124  }
125 
126  if( psSolver ) lsSolver->SetPreconditioner( *psSolver );
127 
128  times[2] = MPI_Wtime() - times[2]; // solver setup time
129  /* Now let us solve the linear system */
130  times[3] = MPI_Wtime(); // reset
131  ierr = lsSolver->Solve( b, x );
132 
133  if( ierr ) cerr << "Error in call to CG/GMRES HYPRE Solver: " << ierr << ".\n" << endl;
134 
135  times[3] = MPI_Wtime() - times[3]; // solver time
136  lsSolver->GetNumIterations( niters );
137  lsSolver->GetFinalResidualNorm( normr );
138  times[4] = MPI_Wtime() - times[0];
139  // x.Print ( "solution.out" );
140 #ifdef MOAB_HAVE_MPI
141  double t4 = times[3];
142  double t4min = 0.0;
143  double t4max = 0.0;
144  double t4avg = 0.0;
145  MPI_Allreduce( &t4, &t4min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD );
146  MPI_Allreduce( &t4, &t4max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
147  MPI_Allreduce( &t4, &t4avg, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
148  t4avg = t4avg / ( (double)size );
149 #endif
150 
151  if( rank == 0 )
152  { // Only PE 0 needs to compute and report timing results
153  // double fniters = niters;
154  // double fnrow = A.NNZ();
155  // double fnnz = A.M();
156  // double fnops_ddot = fniters * 4 * fnrow;
157  // double fnops_waxpby = fniters * 6 * fnrow;
158  // double fnops_sparsemv = fniters * 2 * fnnz;
159  // double fnops = fnops_ddot + fnops_waxpby + fnops_sparsemv;
160  std::cout << "Testing Laplace problem solver with HYPRE interface\n";
161  {
162  std::cout << "\tParallelism\n";
163 #ifdef MOAB_HAVE_MPI
164  std::cout << "Number of MPI ranks: \t" << size << std::endl;
165 #else
166  std::cout << "MPI not enabled\n";
167 #endif
168  }
169  std::cout << "Dimensions (nx*ny*nz): \t(" << nx << "*" << ny << "*" << nz << ")\n";
170  std::cout << "Number of iterations: \t" << niters << std::endl;
171  std::cout << "Final residual: \t" << normr << std::endl;
172  std::cout << "************ Performance Summary (times in sec) *************" << std::endl;
173  {
174  std::cout << "\nTime Summary" << std::endl;
175  std::cout << "Total \t" << times[4] << std::endl;
176  std::cout << "Operator Creation \t" << times[1] << std::endl;
177  std::cout << "Solver Setup \t" << times[2] << std::endl;
178  std::cout << "HYPRE Solver \t" << times[3] << std::endl;
179  std::cout << "Avg. Solver \t" << t4avg << std::endl;
180  }
181  }
182 
183  // Compute difference between known exact solution and computed solution
184  // All processors are needed here.
185  // double residual = 0;
186  // if ((ierr = ComputeLinfError(x, xexact, &residual)))
187  // cerr << "Error in call to ComputeLinfError: " << ierr << ".\n" << endl;
188  // if (rank==0)
189  // cout << "Difference between computed and exact = "
190  // << residual << ".\n" << endl;
191  delete lsSolver;
192  // Finish up
193 #ifdef MOAB_HAVE_MPI
194  MPI_Finalize();
195 #endif
196  return 0;
197 }
198 
200  int ny,
201  int nz,
202  moab::HypreParMatrix& A,
203  moab::HypreParVector& sol,
204  moab::HypreParVector& rhs,
205  moab::HypreParVector& exactsol )
206 {
207 #ifdef DEBUG
208  int debug = 1;
209 #else
210  int debug = 0;
211 #endif
212 #ifdef MOAB_HAVE_MPI
213  int size, rank; // Number of MPI processes, My process ID
214  MPI_Comm_size( MPI_COMM_WORLD, &size );
215  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
216 #else
217  int size = 1; // Serial case (not using MPI)
218  int rank = 0;
219 #endif
220  // Set this bool to true if you want a 7-pt stencil instead of a 27 pt stencil
221  bool use_7pt_stencil = false;
222  const int NNZPERROW = 27;
223 
224  int local_nrow = nx * ny * nz; // This is the size of our subblock
225  assert( local_nrow > 0 ); // Must have something to work with
226  int local_nnz = NNZPERROW * local_nrow; // Approximately 27 nonzeros per row (except for boundary nodes)
227  int total_nrow = 0;
228  MPI_Allreduce( &local_nrow, &total_nrow, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
229 
230  // int total_nrow = local_nrow * size; // Total number of grid points in mesh
231  long long total_nnz =
232  NNZPERROW * (long long)total_nrow; // Approximately 27 nonzeros per row (except for boundary nodes)
233  int start_row = local_nrow * rank; // Each processor gets a section of a chimney stack domain
234  int stop_row = start_row + local_nrow - 1;
235 
236  // Allocate arrays that are of length local_nrow
237  // Eigen::SparseMatrix<double, Eigen::RowMajor> diagMatrix(local_nrow, local_nrow);
238  // diagMatrix.reserve(local_nnz);
239  HYPRE_Int col[2] = { start_row, stop_row };
240  A.resize( total_nrow, col );
241 
242  sol.resize( total_nrow, start_row, stop_row );
243  rhs.resize( total_nrow, start_row, stop_row );
244  exactsol.resize( total_nrow, start_row, stop_row );
245  long long nnzglobal = 0;
246 
247  for( int iz = 0; iz < nz; iz++ )
248  {
249  for( int iy = 0; iy < ny; iy++ )
250  {
251  for( int ix = 0; ix < nx; ix++ )
252  {
253  const int curlocalrow = iz * nx * ny + iy * nx + ix;
254  const int currow = start_row + curlocalrow;
255  int nnzrow = 0;
256  std::vector< double > colvals;
257  std::vector< int > indices;
258 
259  for( int sz = -1; sz <= 1; sz++ )
260  {
261  for( int sy = -1; sy <= 1; sy++ )
262  {
263  for( int sx = -1; sx <= 1; sx++ )
264  {
265  const int curlocalcol = sz * nx * ny + sy * nx + sx;
266  const int curcol = currow + curlocalcol;
267 
268  // Since we have a stack of nx by ny by nz domains , stacking in the z
269  // direction, we check to see if sx and sy are reaching outside of the
270  // domain, while the check for the curcol being valid is sufficient to
271  // check the z values
272  if( ( ix + sx >= 0 ) && ( ix + sx < nx ) && ( iy + sy >= 0 ) && ( iy + sy < ny ) &&
273  ( curcol >= 0 && curcol < total_nrow ) )
274  {
275  if( !use_7pt_stencil || ( sz * sz + sy * sy + sx * sx <= 1 ) )
276  { // This logic will skip over point that are not part of a 7-pt
277  // stencil
278  if( curcol == currow )
279  {
280  colvals.push_back( 27.0 );
281  }
282  else
283  {
284  colvals.push_back( -1.0 );
285  }
286 
287  indices.push_back( curcol );
288  nnzrow++;
289  }
290  }
291  } // end sx loop
292  } // end sy loop
293  } // end sz loop
294 
295  int ncols = indices.size();
296  A.SetValues( 1, &ncols, &currow, indices.data(), colvals.data() );
297  // diagMatrix.set_row_values ( curlocalrow, indices.size(), indices.data(),
298  // colvals.data() );
299  nnzglobal += nnzrow;
300  sol.SetValue( currow, 0.0 );
301  rhs.SetValue( currow, 27.0 - ( (double)( nnzrow - 1 ) ) );
302  exactsol.SetValue( currow, 1.0 );
303  } // end ix loop
304  } // end iy loop
305  } // end iz loop
306 
307  if( debug )
308  cout << "Global size of the matrix: " << total_nrow << " and NNZ (estimate) = " << total_nnz
309  << " NNZ (actual) = " << nnzglobal << endl;
310 
311  if( debug ) cout << "Process " << rank << " of " << size << " has " << local_nrow << endl;
312 
313  if( debug ) cout << " rows. Global rows " << start_row << " through " << stop_row << endl;
314 
315  if( debug ) cout << "Process " << rank << " of " << size << " has " << local_nnz << " nonzeros." << endl;
316 
317  A.FinalizeAssembly();
318  sol.FinalizeAssembly();
319  rhs.FinalizeAssembly();
320  exactsol.FinalizeAssembly();
321  // A.Print("matrix.out");
322  return moab::MB_SUCCESS;
323 }