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 
 64    BoomerAMG amg_solver;
 65    ParaSails ps_solver;
 66    PCG pcg_solver;
 67    IdentitySolver identity;
 68 
 69    /* Initialize MPI */
 70    MPI_Init(&argc, &argv);
 71    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
 72    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
 73    mpi_comm = MPICommunicator::CreateC( &mpicommworld );
 74 
 75    /* Default problem parameters */
 76    n = 33;
 77    solver_id = 0;
 78    print_solution  = 0;
 79 
 80    /* Parse command line */
 81    {
 82       int arg_index = 0;
 83       int print_usage = 0;
 84 
 85       while (arg_index < argc)
 86       {
 87          if ( strcmp(argv[arg_index], "-n") == 0 )
 88          {
 89             arg_index++;
 90             n = atoi(argv[arg_index++]);
 91          }
 92          else if ( strcmp(argv[arg_index], "-solver") == 0 )
 93          {
 94             arg_index++;
 95             solver_id = atoi(argv[arg_index++]);
 96          }
 97          else if ( strcmp(argv[arg_index], "-print_solution") == 0 )
 98          {
 99             arg_index++;
100             print_solution = 1;
101          }
102          else if ( strcmp(argv[arg_index], "-help") == 0 )
103          {
104             print_usage = 1;
105             break;
106          }
107          else
108          {
109             arg_index++;
110          }
111       }
112 
113       if ((print_usage) && (myid == 0))
114       {
115          printf("\n");
116          printf("Usage: %s [<options>]\n", argv[0]);
117          printf("\n");
118          printf("  -n <n>              : problem size in each direction (default: 33)\n");
119          printf("  -solver <ID>        : solver ID\n");
120          printf("                        0  - AMG (default) \n");
121          printf("                        1  - AMG-PCG\n");
122          printf("                        8  - ParaSails-PCG\n");
123          printf("                        50 - PCG\n");
124          printf("  -print_solution     : print the solution vector\n");
125          printf("\n");
126       }
127 
128       if (print_usage)
129       {
130          MPI_Finalize();
131          return (0);
132       }
133    }
134 
135    /* Preliminaries: want at least one processor per row */
136    if (n*n < num_procs) n = int(sqrt(num_procs)) + 1;
137    N = n*n; /* global number of rows */
138    h = 1.0/(n+1); /* mesh size*/
139    h2 = h*h;
140 
141    /* Each processor knows only of its own rows - the range is denoted by ilower
142       and upper.  Here we partition the rows. We account for the fact that
143       N may not divide evenly by the number of processors. */
144    local_size = N/num_procs;
145    extra = N - local_size*num_procs;
146 
147    ilower = local_size*myid;
148    ilower += hypre_min(myid, extra);
149 
150    iupper = local_size*(myid+1);
151    iupper += hypre_min(myid+1, extra);
152    iupper = iupper - 1;
153 
154    /* How many rows do I have? */
155    local_size = iupper - ilower + 1;
156 
157    /* Create the matrix.
158       Note that this is a square matrix, so we indicate the row partition
159       size twice (since number of rows = number of cols) */
160    parcsr_A = IJParCSRMatrix::Create( mpi_comm,
161                                         ilower, iupper, ilower, iupper );
162 
163    op_A = parcsr_A; /* we can eliminate op_A later, it's really needed only in C */
164 
165    /* Choose a parallel csr format storage (see the User's Manual) */
166    /* Note: Here the HYPRE interface requires a SetObjectType call.
167       I am using the bHYPRE interface in a way which does not because
168       the object type is already specified through the class name. */
169 
170    /* Initialize before setting coefficients */
171    parcsr_A.Initialize();
172 
173    /* Now go through my local rows and set the matrix entries.
174       Each row has at most 5 entries. For example, if n=3:
175 
176       A = [M -I 0; -I M -I; 0 -I M]
177       M = [4 -1 0; -1 4 -1; 0 -1 4]
178 
179       Note that here we are setting one row at a time, though
180       one could set all the rows together (see the User's Manual).
181    */
182    {
183       int nnz;
184       double values[5];
185       int cols[5];
186 
187       for (i = ilower; i <= iupper; i++)
188       {
189          nnz = 0;
190 
191          /* The left identity block:position i-n */
192          if ((i-n)>=0)
193          {
194 	    cols[nnz] = i-n;
195 	    values[nnz] = -1.0;
196 	    nnz++;
197          }
198 
199          /* The left -1: position i-1 */
200          if (i%n)
201          {
202             cols[nnz] = i-1;
203             values[nnz] = -1.0;
204             nnz++;
205          }
206 
207          /* Set the diagonal: position i */
208          cols[nnz] = i;
209          values[nnz] = 4.0;
210          nnz++;
211 
212          /* The right -1: position i+1 */
213          if ((i+1)%n)
214          {
215             cols[nnz] = i+1;
216             values[nnz] = -1.0;
217             nnz++;
218          }
219 
220          /* The right identity block:position i+n */
221          if ((i+n)< N)
222          {
223             cols[nnz] = i+n;
224             values[nnz] = -1.0;
225             nnz++;
226          }
227 
228          /* Set the values for row i */
229          parcsr_A.SetValues( 1, &nnz, &i, cols, values, 5 );
230       }
231    }
232 
233    /* Assemble after setting the coefficients */
234    parcsr_A.Assemble();
235 
236    /* Create the rhs and solution */
237    par_b = IJParCSRVector::Create( mpi_comm, ilower, iupper );
238 
239    par_b.Initialize();
240 
241    par_x = IJParCSRVector::Create( mpi_comm, ilower, iupper );
242 
243    par_x.Initialize();
244 
245    /* Set the rhs values to h^2 and the solution to zero */
246    {
247       double *rhs_values, *x_values;
248       int    *rows;
249 
250       rhs_values = new double[local_size];
251       x_values = new double[local_size];
252       rows = new int[local_size];
253 
254       for (i=0; i<local_size; i++)
255       {
256          rhs_values[i] = h2;
257          x_values[i] = 0.0;
258          rows[i] = ilower + i;
259       }
260 
261       par_b.SetValues( local_size, rows, rhs_values );
262       par_x.SetValues( local_size, rows, x_values );
263 
264       delete[] x_values;
265       delete[] rhs_values;
266       delete[] rows;
267    }
268 
269    par_b.Assemble();
270    par_x.Assemble();
271 
272    /* Choose a solver and solve the system */
273 
274    /* AMG */
275    if (solver_id == 0)
276    {
277       int num_iterations;
278       double final_res_norm;
279 
280       /* Create solver */
281       amg_solver = BoomerAMG::Create( mpi_comm, parcsr_A );
282 
283       /* Set some parameters (See Reference Manual for more parameters) */
284       amg_solver.SetIntParameter( "PrintLevel", 3 );  /* print solve info + parameters */
285       amg_solver.SetIntParameter( "CoarsenType", 6); /* Falgout coarsening */
286       amg_solver.SetIntParameter( "RelaxType", 3);   /* G-S/Jacobi hybrid relaxation */
287       amg_solver.SetIntParameter( "NumSweeps", 1);   /* Sweeeps on each level */
288       amg_solver.SetIntParameter( "MaxLevels", 20);  /* maximum number of levels */
289       amg_solver.SetDoubleParameter( "Tolerance", 1e-7);      /* conv. tolerance */
290 
291       /* Now setup and solve! */
292       amg_solver.Setup( par_b, par_x );
293       amg_solver.Apply( par_b, par_x );
294 
295       /* Run info - needed logging turned on */
296 
297       ierr += amg_solver.GetIntValue( "NumIterations", num_iterations );
298       amg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
299 
300       if (myid == 0)
301       {
302          printf("\n");
303          printf("Iterations = %d\n", num_iterations);
304          printf("Final Relative Residual Norm = %e\n", final_res_norm);
305          printf("\n");
306       }
307 
308       /* Destroy solver */
309       /* In C++, unlike C, deleteRef of amg_solver is not needed here -
310          it happens automatically. */
311    }
312 
313    /* PCG */
314    else if (solver_id == 50)
315    {
316       int num_iterations;
317       double final_res_norm;
318 
319       /* Create solver */
320       pcg_solver = PCG::Create( mpi_comm, op_A );
321 
322       /* Set some parameters (See Reference Manual for more parameters) */
323       pcg_solver.SetIntParameter( "MaxIter", 1000 ); /* max iterations */
324       pcg_solver.SetDoubleParameter( "Tolerance", 1e-7 ); /* conv. tolerance */
325       pcg_solver.SetIntParameter( "TwoNorm", 1 ); /* use the two norm as the stopping criteria */
326       pcg_solver.SetIntParameter( "PrintLevel", 2 ); /* prints out the iteration info */
327       pcg_solver.SetIntParameter( "Logging", 1 ); /* needed to get run info later */
328 
329       identity = IdentitySolver::Create( mpi_comm );
330       pcg_solver.SetPreconditioner( identity );
331 
332       /* Now setup and solve! */
333       pcg_solver.Setup( par_b, par_x );
334       pcg_solver.Apply( par_b, par_x );
335 
336       /* Run info - needed logging turned on */
337       pcg_solver.GetIntValue( "NumIterations", num_iterations );
338       pcg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
339       if (myid == 0)
340       {
341          printf("\n");
342          printf("Iterations = %d\n", num_iterations);
343          printf("Final Relative Residual Norm = %e\n", final_res_norm);
344          printf("\n");
345       }
346 
347       /* Destroy solvers */
348       /* In C++, unlike C, deleteRef's of solvers are not needed here -
349          it happens automatically. */
350    }
351    /* PCG with AMG preconditioner */
352    else if (solver_id == 1)
353    {
354       int num_iterations;
355       double final_res_norm;
356 
357       /* Create solver */
358       pcg_solver = PCG::Create( mpi_comm, op_A );
359 
360       /* Set some parameters (See Reference Manual for more parameters) */
361       pcg_solver.SetIntParameter( "MaxIter", 1000 ); /* max iterations */
362       pcg_solver.SetDoubleParameter( "Tolerance", 1e-7 ); /* conv. tolerance */
363       pcg_solver.SetIntParameter( "TwoNorm", 1 ); /* use the two norm as the stopping criteria */
364       pcg_solver.SetIntParameter( "PrintLevel", 2 ); /* prints out the iteration info */
365       pcg_solver.SetIntParameter( "Logging", 1 ); /* needed to get run info later */
366 
367       /* Now set up the AMG preconditioner and specify any parameters */
368       amg_solver = BoomerAMG::Create( mpi_comm, parcsr_A );
369       amg_solver.SetIntParameter( "PrintLevel", 1 ); /* print amg solution info*/
370       amg_solver.SetIntParameter( "CoarsenType", 6); /* Falgout coarsening */
371       amg_solver.SetIntParameter( "RelaxType", 6);   /* Sym G-S/Jacobi hybrid relaxation */
372       amg_solver.SetIntParameter( "NumSweeps", 1);   /* Sweeeps on each level */
373       amg_solver.SetDoubleParameter( "Tolerance", 1e-3);      /* conv. tolerance */
374       amg_solver.SetIntParameter( "MaxIter", 1 ); /* do only one iteration! */
375 
376       /* Set the PCG preconditioner */
377       pcg_solver.SetPreconditioner( amg_solver );
378 
379       /* Now setup and solve! */
380       pcg_solver.Setup( par_b, par_x );
381       pcg_solver.Apply( par_b, par_x );
382 
383       /* Run info - needed logging turned on */
384       pcg_solver.GetIntValue( "NumIterations", num_iterations );
385       pcg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
386       if (myid == 0)
387       {
388          printf("\n");
389          printf("Iterations = %d\n", num_iterations);
390          printf("Final Relative Residual Norm = %e\n", final_res_norm);
391          printf("\n");
392       }
393 
394       /* Destroy solver and preconditioner */
395       /* In C++, unlike C, deleteRef's of solvers are not needed here -
396          it happens automatically. */
397    }
398 
399    /* PCG with Parasails Preconditioner */
400    else if (solver_id == 8)
401    {
402       int    num_iterations;
403       double final_res_norm;
404 
405       int      sai_max_levels = 1;
406       double   sai_threshold = 0.1;
407       double   sai_filter = 0.05;
408       int      sai_sym = 1;
409 
410       /* Create solver */
411       pcg_solver = PCG::Create( mpi_comm, op_A );
412 
413       /* Set some parameters (See Reference Manual for more parameters) */
414       pcg_solver.SetIntParameter( "MaxIter", 1000 ); /* max iterations */
415       pcg_solver.SetDoubleParameter( "Tolerance", 1e-7 ); /* conv. tolerance */
416       pcg_solver.SetIntParameter( "TwoNorm", 1 ); /* use the two norm as the stopping criteria */
417       pcg_solver.SetIntParameter( "PrintLevel", 2 ); /* prints out the iteration info */
418       pcg_solver.SetIntParameter( "Logging", 1 ); /* needed to get run info later */
419 
420       /* Now set up the ParaSails preconditioner and specify any parameters */
421       ps_solver = ParaSails::Create( mpi_comm, parcsr_A );
422 
423       /* Set some parameters (See Reference Manual for more parameters) */
424       ps_solver.SetDoubleParameter( "Thresh", sai_threshold );
425       ps_solver.SetIntParameter( "Nlevels", sai_max_levels );
426       ps_solver.SetDoubleParameter( "Filter", sai_filter );
427       ps_solver.SetIntParameter( "Sym", sai_sym );
428       ps_solver.SetIntParameter( "Logging", 3 );
429 
430       /* Set the PCG preconditioner */
431       pcg_solver.SetPreconditioner( ps_solver );
432 
433       /* Now setup and solve! */
434       pcg_solver.Setup( par_b, par_x);
435       pcg_solver.Apply( par_b, par_x);
436 
437 
438       /* Run info - needed logging turned on */
439       pcg_solver.GetIntValue( "NumIterations", num_iterations );
440       pcg_solver.GetDoubleValue( "RelResidualNorm", final_res_norm );
441       if (myid == 0)
442       {
443          printf("\n");
444          printf("Iterations = %d\n", num_iterations);
445          printf("Final Relative Residual Norm = %e\n", final_res_norm);
446          printf("\n");
447       }
448 
449       /* Destroy solver and preconditioner */
450       /* In C++, unlike C, deleteRef's of solvers are not needed here -
451          it happens automatically. */
452    }
453    else
454    {
455       if (myid ==0) printf("Invalid solver id specified.\n");
456    }
457 
458    /* Print the solution */
459    if (print_solution)
460       par_x.Print( "ij.out.x" );
461 
462    /* Clean up */
463    /* In C++, unlike C, deleteRef gets called automatically, so we don't
464       need any explicit cleanup. */
465 
466    hypre_assert( ierr == 0 );
467 
468    /* Finalize MPI*/
469    MPI_Finalize();
470 
471    return(0);
472 }


syntax highlighted by Code2HTML, v. 0.9.1