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