download the original source code.
  1 /*
  2    Example 5
  3 
  4    Interface:    Linear-Algebraic (IJ), Babel-based version
  5 
  6    Compile with: make ex5bxx
  7 
  8    Sample run:   mpirun -np 4 ex5bxx
  9 
 10    Description:  This example solves the 2-D
 11                  Laplacian problem with zero boundary conditions
 12                  on an nxn grid.  The number of unknowns is N=n^2.
 13                  The standard 5-point stencil is used, and we solve
 14                  for the interior nodes only.
 15 
 16                  This example solves the same problem as Example 3.
 17                  Available solvers are AMG, PCG, and PCG with AMG or
 18                  Parasails preconditioners.
 19 
 20 */
 21 
 22 #include <math.h>
 23 #include <assert.h>
 24 #include "_hypre_utilities.h"
 25 #include "HYPRE_krylov.h"
 26 #include "HYPRE.h"
 27 #include "HYPRE_parcsr_ls.h"
 28 
 29 /* Babel interface headers */
 30 #include "bHYPRE.hxx"
 31 #include "bHYPRE_Vector.h"
 32 #include "bHYPRE_IJParCSRMatrix.h"
 33 #include "bHYPRE_IJParCSRVector.h"
 34 #include "bHYPRE_ParCSRDiagScale.h"
 35 #include "bHYPRE_BoomerAMG.h"
 36 
 37 int main (int argc, char *argv[])
 38 {
 39    using namespace ::bHYPRE;
 40    int i;
 41    int myid, num_procs;
 42    int N, n;
 43 
 44    int ilower, iupper;
 45    int local_size, extra;
 46 
 47    int solver_id;
 48    int print_solution;
 49 
 50    double h, h2;
 51    MPI_Comm mpicommworld = MPI_COMM_WORLD;
 52 
 53    int ierr = 0;
 54    /* If this gets set to anything else, it's an error.
 55     Most functions return error flags, 0 unless there's an error.
 56     For clarity, they aren't checked much in this file. */
 57 
 58    MPICommunicator mpi_comm;
 59    IJParCSRMatrix parcsr_A;
 60    Operator  op_A;
 61    IJParCSRVector par_b;
 62    IJParCSRVector par_x;
 63    Vector vec_x;
 64 
 65    BoomerAMG amg_solver;
 66    ParaSails ps_solver;
 67    PCG pcg_solver;
 68    IdentitySolver identity;
 69 
 70    /* Initialize MPI */
 71    MPI_Init(&argc, &argv);
 72    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
 73    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
 74    mpi_comm = MPICommunicator::CreateC( &mpicommworld );
 75 
 76    /* Default problem parameters */
 77    n = 33;
 78    solver_id = 0;
 79    print_solution  = 0;
 80 
 81    /* Parse command line */
 82    {
 83       int arg_index = 0;
 84       int print_usage = 0;
 85 
 86       while (arg_index < argc)
 87       {
 88          if ( strcmp(argv[arg_index], "-n") == 0 )
 89          {
 90             arg_index++;
 91             n = atoi(argv[arg_index++]);
 92          }
 93          else if ( strcmp(argv[arg_index], "-solver") == 0 )
 94          {
 95             arg_index++;
 96             solver_id = atoi(argv[arg_index++]);
 97          }
 98          else if ( strcmp(argv[arg_index], "-print_solution") == 0 )
 99          {
100             arg_index++;
101             print_solution = 1;
102          }
103          else if ( strcmp(argv[arg_index], "-help") == 0 )
104          {
105             print_usage = 1;
106             break;
107          }
108          else
109          {
110             arg_index++;
111          }
112       }
113 
114       if ((print_usage) && (myid == 0))
115       {
116          printf("\n");
117          printf("Usage: %s [<options>]\n", argv[0]);
118          printf("\n");
119          printf("  -n <n>              : problem size in each direction (default: 33)\n");
120          printf("  -solver <ID>        : solver ID\n");
121          printf("                        0  - AMG (default) \n");
122          printf("                        1  - AMG-PCG\n");
123          printf("                        8  - ParaSails-PCG\n");
124          printf("                        50 - PCG\n");
125          printf("  -print_solution     : print the solution vector\n");
126          printf("\n");
127       }
128 
129       if (print_usage)
130       {
131          MPI_Finalize();
132          return (0);
133       }
134    }
135 
136    /* Preliminaries: want at least one processor per row */
137    if (n*n < num_procs) n = int(sqrt(num_procs)) + 1;
138    N = n*n; /* global number of rows */
139    h = 1.0/(n+1); /* mesh size*/
140    h2 = h*h;
141 
142    /* Each processor knows only of its own rows - the range is denoted by ilower
143       and upper.  Here we partition the rows. We account for the fact that
144       N may not divide evenly by the number of processors. */
145    local_size = N/num_procs;
146    extra = N - local_size*num_procs;
147 
148    ilower = local_size*myid;
149    ilower += hypre_min(myid, extra);
150 
151    iupper = local_size*(myid+1);
152    iupper += hypre_min(myid+1, extra);
153    iupper = iupper - 1;
154 
155    /* How many rows do I have? */
156    local_size = iupper - ilower + 1;
157 
158    /* Create the matrix.
159       Note that this is a square matrix, so we indicate the row partition
160       size twice (since number of rows = number of cols) */
161    parcsr_A = IJParCSRMatrix::Create( mpi_comm,
162                                         ilower, iupper, ilower, iupper );
163 
164    op_A = parcsr_A; /* we can eliminate op_A later, it's really needed only in C */
165 
166    /* Choose a parallel csr format storage (see the User's Manual) */
167    /* Note: Here the HYPRE interface requires a SetObjectType call.
168       I am using the bHYPRE interface in a way which does not because
169       the object type is already specified through the class name. */
170 
171    /* Initialize before setting coefficients */
172    parcsr_A.Initialize();
173 
174    /* Now go through my local rows and set the matrix entries.
175       Each row has at most 5 entries. For example, if n=3:
176 
177       A = [M -I 0; -I M -I; 0 -I M]
178       M = [4 -1 0; -1 4 -1; 0 -1 4]
179 
180       Note that here we are setting one row at a time, though
181       one could set all the rows together (see the User's Manual).
182    */
183    {
184       int nnz;
185       double values[5];
186       int cols[5];
187 
188       for (i = ilower; i <= iupper; i++)
189       {
190          nnz = 0;
191 
192          /* The left identity block:position i-n */
193          if ((i-n)>=0)
194          {
195 	    cols[nnz] = i-n;
196 	    values[nnz] = -1.0;
197 	    nnz++;
198          }
199 
200          /* The left -1: position i-1 */
201          if (i%n)
202          {
203             cols[nnz] = i-1;
204             values[nnz] = -1.0;
205             nnz++;
206          }
207 
208          /* Set the diagonal: position i */
209          cols[nnz] = i;
210          values[nnz] = 4.0;
211          nnz++;
212 
213          /* The right -1: position i+1 */
214          if ((i+1)%n)
215          {
216             cols[nnz] = i+1;
217             values[nnz] = -1.0;
218             nnz++;
219          }
220 
221          /* The right identity block:position i+n */
222          if ((i+n)< N)
223          {
224             cols[nnz] = i+n;
225             values[nnz] = -1.0;
226             nnz++;
227          }
228 
229          /* Set the values for row i */
230          parcsr_A.SetValues( 1, &nnz, &i, cols, values, 5 );
231       }
232    }
233 
234    /* Assemble after setting the coefficients */
235    parcsr_A.Assemble();
236 
237    /* Create the rhs and solution */
238    par_b = IJParCSRVector::Create( mpi_comm, ilower, iupper );
239 
240    par_b.Initialize();
241 
242    par_x = IJParCSRVector::Create( mpi_comm, ilower, iupper );
243 
244    par_x.Initialize();
245 
246    /* Set the rhs values to h^2 and the solution to zero */
247    {
248       double *rhs_values, *x_values;
249       int    *rows;
250 
251       rhs_values = new double[local_size];
252       x_values = new double[local_size];
253       rows = new int[local_size];
254 
255       for (i=0; i<local_size; i++)
256       {
257          rhs_values[i] = h2;
258          x_values[i] = 0.0;
259          rows[i] = ilower + i;
260       }
261 
262       par_b.SetValues( local_size, rows, rhs_values );
263       par_x.SetValues( local_size, rows, x_values );
264 
265       delete[] x_values;
266       delete[] rhs_values;
267       delete[] rows;
268    }
269 
270    par_b.Assemble();
271    par_x.Assemble();
272 
273    /* Choose a solver and solve the system */
274 
275    /* AMG */
276    if (solver_id == 0)
277    {
278       int num_iterations;
279       double final_res_norm;
280 
281       /* Create solver */
282       amg_solver = BoomerAMG::Create( mpi_comm, parcsr_A );
283 
284       /* Set some parameters (See Reference Manual for more parameters) */
285       amg_solver.SetIntParameter( "PrintLevel", 3 );  /* print solve info + parameters */
286       amg_solver.SetIntParameter( "CoarsenType", 6); /* Falgout coarsening */
287       amg_solver.SetIntParameter( "RelaxType", 3);   /* G-S/Jacobi hybrid relaxation */
288       amg_solver.SetIntParameter( "NumSweeps", 1);   /* Sweeeps on each level */
289       amg_solver.SetIntParameter( "MaxLevels", 20);  /* maximum number of levels */
290       amg_solver.SetDoubleParameter( "Tolerance", 1e-7);      /* conv. tolerance */
291 
292       /* Now setup and solve! */
293       // In C++, use of the Apply function is slightly more complicated than in other
294       // languages.
295       //   The second argument, the solution (and initial guess), is declared inout in
296       // Interfaces.idl.  For C++, Babel implements an inout (or out) argument as a
297       // reference argument, and obviously not a const one.
298       //   So it is important not to implicitly ask the C++ environment for a type
299       // conversion when supplying the second argument - results will be unpredictable!
300       //   Our solution vector is par_x, declared type IJParCSRVector, derived from
301       // Vector. In other languages we would use par_x directly for the second argument.
302       // In C++ we must declare a Vector, vec_x, for use as the second argument.
303       //   Fortunately, an assignment is all you have to do to set up vec_x.
304       // Babel casts and code other inside the Apply function will recover the original
305       // IJParCSRVector, par_x, to make sure it gets computed correctly.
306       amg_solver.Setup( par_b, par_x );
307       vec_x = par_x;
308       amg_solver.Apply( par_b, vec_x );
309 
310       /* Run info - needed logging turned on */
311 
312       ierr += amg_solver.GetIntValue( "NumIterations", num_iterations );
313       amg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
314 
315       if (myid == 0)
316       {
317          printf("\n");
318          printf("Iterations = %d\n", num_iterations);
319          printf("Final Relative Residual Norm = %e\n", final_res_norm);
320          printf("\n");
321       }
322 
323       /* Destroy solver */
324       /* In C++, unlike C, deleteRef of amg_solver is not needed here -
325          it happens automatically. */
326    }
327 
328    /* PCG */
329    else if (solver_id == 50)
330    {
331       int num_iterations;
332       double final_res_norm;
333 
334       /* Create solver */
335       pcg_solver = PCG::Create( mpi_comm, op_A );
336 
337       /* Set some parameters (See Reference Manual for more parameters) */
338       pcg_solver.SetIntParameter( "MaxIter", 1000 ); /* max iterations */
339       pcg_solver.SetDoubleParameter( "Tolerance", 1e-7 ); /* conv. tolerance */
340       pcg_solver.SetIntParameter( "TwoNorm", 1 ); /* use the two norm as the stopping criteria */
341       pcg_solver.SetIntParameter( "PrintLevel", 2 ); /* prints out the iteration info */
342       pcg_solver.SetIntParameter( "Logging", 1 ); /* needed to get run info later */
343 
344       identity = IdentitySolver::Create( mpi_comm );
345       pcg_solver.SetPreconditioner( identity );
346 
347       /* Now setup and solve! */
348       // See comments for solver 0 on Apply and vec_x.
349       pcg_solver.Setup( par_b, par_x );
350       vec_x = par_x;
351       pcg_solver.Apply( par_b, vec_x );
352 
353       /* Run info - needed logging turned on */
354       pcg_solver.GetIntValue( "NumIterations", num_iterations );
355       pcg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
356       if (myid == 0)
357       {
358          printf("\n");
359          printf("Iterations = %d\n", num_iterations);
360          printf("Final Relative Residual Norm = %e\n", final_res_norm);
361          printf("\n");
362       }
363 
364       /* Destroy solvers */
365       /* In C++, unlike C, deleteRef's of solvers are not needed here -
366          it happens automatically. */
367    }
368    /* PCG with AMG preconditioner */
369    else if (solver_id == 1)
370    {
371       int num_iterations;
372       double final_res_norm;
373 
374       /* Create solver */
375       pcg_solver = PCG::Create( mpi_comm, op_A );
376 
377       /* Set some parameters (See Reference Manual for more parameters) */
378       pcg_solver.SetIntParameter( "MaxIter", 1000 ); /* max iterations */
379       pcg_solver.SetDoubleParameter( "Tolerance", 1e-7 ); /* conv. tolerance */
380       pcg_solver.SetIntParameter( "TwoNorm", 1 ); /* use the two norm as the stopping criteria */
381       pcg_solver.SetIntParameter( "PrintLevel", 2 ); /* prints out the iteration info */
382       pcg_solver.SetIntParameter( "Logging", 1 ); /* needed to get run info later */
383 
384       /* Now set up the AMG preconditioner and specify any parameters */
385       amg_solver = BoomerAMG::Create( mpi_comm, parcsr_A );
386       amg_solver.SetIntParameter( "PrintLevel", 1 ); /* print amg solution info*/
387       amg_solver.SetIntParameter( "CoarsenType", 6); /* Falgout coarsening */
388       amg_solver.SetIntParameter( "RelaxType", 6);   /* Sym G-S/Jacobi hybrid relaxation */
389       amg_solver.SetIntParameter( "NumSweeps", 1);   /* Sweeeps on each level */
390       amg_solver.SetDoubleParameter( "Tolerance", 0);      /* conv. tolerance */
391       amg_solver.SetIntParameter( "MaxIter", 1 ); /* do only one iteration! */
392 
393       /* Set the PCG preconditioner */
394       pcg_solver.SetPreconditioner( amg_solver );
395 
396       /* Now setup and solve! */
397       // See comments for solver 0 on Apply and vec_x.
398       pcg_solver.Setup( par_b, par_x );
399       vec_x = par_x;
400       pcg_solver.Apply( par_b, vec_x );
401 
402       /* Run info - needed logging turned on */
403       pcg_solver.GetIntValue( "NumIterations", num_iterations );
404       pcg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
405       if (myid == 0)
406       {
407          printf("\n");
408          printf("Iterations = %d\n", num_iterations);
409          printf("Final Relative Residual Norm = %e\n", final_res_norm);
410          printf("\n");
411       }
412 
413       /* Destroy solver and preconditioner */
414       /* In C++, unlike C, deleteRef's of solvers are not needed here -
415          it happens automatically. */
416    }
417 
418    /* PCG with Parasails Preconditioner */
419    else if (solver_id == 8)
420    {
421       int    num_iterations;
422       double final_res_norm;
423 
424       int      sai_max_levels = 1;
425       double   sai_threshold = 0.1;
426       double   sai_filter = 0.05;
427       int      sai_sym = 1;
428 
429       /* Create solver */
430       pcg_solver = PCG::Create( mpi_comm, op_A );
431 
432       /* Set some parameters (See Reference Manual for more parameters) */
433       pcg_solver.SetIntParameter( "MaxIter", 1000 ); /* max iterations */
434       pcg_solver.SetDoubleParameter( "Tolerance", 1e-7 ); /* conv. tolerance */
435       pcg_solver.SetIntParameter( "TwoNorm", 1 ); /* use the two norm as the stopping criteria */
436       pcg_solver.SetIntParameter( "PrintLevel", 2 ); /* prints out the iteration info */
437       pcg_solver.SetIntParameter( "Logging", 1 ); /* needed to get run info later */
438 
439       /* Now set up the ParaSails preconditioner and specify any parameters */
440       ps_solver = ParaSails::Create( mpi_comm, parcsr_A );
441 
442       /* Set some parameters (See Reference Manual for more parameters) */
443       ps_solver.SetDoubleParameter( "Thresh", sai_threshold );
444       ps_solver.SetIntParameter( "Nlevels", sai_max_levels );
445       ps_solver.SetDoubleParameter( "Filter", sai_filter );
446       ps_solver.SetIntParameter( "Sym", sai_sym );
447       ps_solver.SetIntParameter( "Logging", 3 );
448 
449       /* Set the PCG preconditioner */
450       pcg_solver.SetPreconditioner( ps_solver );
451 
452       /* Now setup and solve! */
453       // See comments for solver 0 on Apply and vec_x.
454       pcg_solver.Setup( par_b, par_x);
455       vec_x = par_x;
456       pcg_solver.Apply( par_b, vec_x);
457 
458 
459       /* Run info - needed logging turned on */
460       pcg_solver.GetIntValue( "NumIterations", num_iterations );
461       pcg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
462       if (myid == 0)
463       {
464          printf("\n");
465          printf("Iterations = %d\n", num_iterations);
466          printf("Final Relative Residual Norm = %e\n", final_res_norm);
467          printf("\n");
468       }
469 
470       /* Destroy solver and preconditioner */
471       /* In C++, unlike C, deleteRef's of solvers are not needed here -
472          it happens automatically. */
473    }
474    else
475    {
476       if (myid ==0) printf("Invalid solver id specified.\n");
477    }
478 
479    /* Print the solution */
480    if (print_solution)
481       par_x.Print( "ij.out.x" );
482 
483    /* Clean up */
484    /* In C++, unlike C, deleteRef gets called automatically, so we don't
485       need any explicit cleanup. */
486 
487    hypre_assert( ierr == 0 );
488 
489    /* Finalize MPI*/
490    MPI_Finalize();
491 
492    return(0);
493 }


syntax highlighted by Code2HTML, v. 0.9.1