biharmonic_preconditioner.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26// Config header
27#ifdef HAVE_CONFIG_H
28#include <oomph-lib-config.h>
29#endif
30
31
32// oomph-lib includes
34
35
36namespace oomph
37{
38#ifdef OOMPH_HAS_HYPRE
39
40 //=============================================================================
41 // defaults settings for the Hypre solver (AMG) when used as the approximate
42 // linear solver for the Schur complement (non-compound) linear subsidiary
43 // linear systems
44 //=============================================================================
45 namespace Biharmonic_schur_complement_Hypre_defaults
46 {
47 /// smoother type - Gauss Seidel: 1
48 unsigned AMG_smoother = 1;
49
50 /// amg coarsening strategy: classical Ruge Stueben: 1
51 unsigned AMG_coarsening = 1;
52
53 /// number of V cycles: 2
54 unsigned N_cycle = 2;
55
56 /// amg strength parameter: 0.25 -- optimal for 2d
57 double AMG_strength = 0.25;
58
59 /// jacobi damping -- hierher not used 0.1
60 double AMG_jacobi_damping = 0.1;
61
62 /// amg smoother iterations
64
65 /// set the defaults
67 {
68 // use AMG preconditioner
69 hypre_prec_pt->hypre_method() = HypreSolver::BoomerAMG;
70
71 // Smoother types
72 hypre_prec_pt->amg_simple_smoother() = AMG_smoother;
73
74 // jacobi damping
75 // hypre_prec_pt->amg_damping() = AMG_jacobi_damping;
76
77 // coarsening stategy
78 hypre_prec_pt->amg_coarsening() = AMG_coarsening;
79
80 oomph_info << "Current number of v cycles: "
81 << hypre_prec_pt->amg_iterations() << std::endl;
82
83 // number of v-cycles
84 hypre_prec_pt->amg_iterations() = N_cycle;
85
86 oomph_info << "Re-assigned number of v cycles: "
87 << hypre_prec_pt->amg_iterations() << std::endl;
88
89 // strength parameter
90 hypre_prec_pt->amg_strength() = AMG_strength;
91
92 // hierher new
93 oomph_info << "Current number of amg smoother iterations: "
94 << hypre_prec_pt->amg_smoother_iterations() << std::endl;
95
96 hypre_prec_pt->amg_smoother_iterations() = AMG_smoother_iterations;
97
98 oomph_info << "Re-assigned number of amg smoother iterations: "
99 << hypre_prec_pt->amg_smoother_iterations() << std::endl;
100 }
101 } // namespace Biharmonic_schur_complement_Hypre_defaults
102#endif
103
104 //===========================================================================
105 /// setup for the biharmonic preconditioner
106 //===========================================================================
108 {
109 // clean up
110 this->clean_up_memory();
111
112 // paranoid check that teh bulk element mesh has been set
113#ifdef PARANOID
114 if (Bulk_element_mesh_pt == 0)
115 {
116 std::ostringstream error_message;
117 error_message << "The bulk element mesh has not been passed to "
118 "bulk_element_mesh_pt()";
119 throw OomphLibError(
121 }
122#endif
123
124 // setup the mesh
126
127 // setup the blocks look up schemes
128 this->block_setup();
129
130 // determine whether this preconditioner has 4 or 5 block types and set
131 // Nblock_types if neccessary
132 // unsigned n_row = this->master_nrow();
133 // bool nblock_type_check = true;
134 // for (unsigned i = 0; i < n_row; i++)
135 // {
136 // if (this->block_number(i) == 4) { nblock_type_check = false; }
137 // }
138 // if (nblock_type_check) { Nblock_types = 4; }
139 //
140
141 // check the preconditioner type is acceptable
142#ifdef PARANOID
143 if (Preconditioner_type != 0 && Preconditioner_type != 1 &&
145 {
146 std::ostringstream error_message;
147 error_message << "Preconditioner_type must be equal to 0 (BBD exact), 1 "
148 "(inexact BBD with LU),"
149 << " 2 (inexact BBD with AMG) or 3 (exact BD).";
150 throw OomphLibError(
152 }
153#endif
154
155 // create the preconditioners
156 bool use_amg = true;
157 bool retain_all_blocks = false;
158 switch (Preconditioner_type)
159 {
160 // Exact BBD
161 case 0:
162
163 retain_all_blocks = false;
168 oomph_info << "Using exact BBD\n";
169 break;
170
171 // Inexact BBD with LU
172 case 1:
173
174 use_amg = false;
178 oomph_info << "Using inexact BBD with LU\n";
179 break;
180
181
182 // Inexact BBD with AMG
183 case 2:
184
185 use_amg = true;
189 oomph_info << "Using inexact BBD with AMG\n";
190 break;
191
192 /// Exact BD
193 case 3:
194
195 retain_all_blocks = true;
200 oomph_info << "Using exact BD\n";
201 break;
202
203 default:
204
205 throw OomphLibError("Wrong type of preconditioner.",
208 }
209
210
211 // setup sub preconditioner pt 1
213
214 // get the matrix ans setup sub preconditioner pt 2
216 this->get_block(3, 3, *j_33_pt);
218 delete j_33_pt;
219 j_33_pt = 0;
220
221 // if the block preconditioner has 5 block types setup the preconditioner
222 // for the 5th block diagonal block (Matrix is also diagonal hence a
223 // diagonal preconditioner is sufficient in the exact biharmonic
224 // preconditioner case as well)
225 if (this->nblock_types() == 5)
226 {
227 // get the matrix for block J_33
229 this->get_block(4, 4, *j_44_pt);
230
231 // setup the hijacked sub preconditioner
234 delete j_44_pt;
235 j_44_pt = 0;
236 }
237 }
238
239
240 //============================================================================
241 /// preconditioner solve for the biharmonic preconditioner
242 //============================================================================
244 DoubleVector& z)
245 {
246 // zero z
247 z.initialise(0.0);
248
249 // solve sub preconditioner 1
251
252 // solve sub preconditioner 2
258
259 // solve the hijacked sub block preconditioner if required
260 if (this->nblock_types() == 5)
261 {
262 block_r.clear();
263 block_z.clear();
266 block_z);
268 }
269 }
270
271 //============================================================================
272 /// setup for the exact sub biharmonic preconditioner
273 //============================================================================
275 {
276 // clean up memory first
277 this->clean_up_memory();
278
279 // setup
280 this->block_setup();
281
282 // Number of block types
283 unsigned n_block_types = this->nblock_types();
284
285 // check for required number of blocks
286#ifdef PARANOID
287 if (n_block_types != 3)
288 {
289 std::ostringstream error_message;
290 error_message
291 << "This preconditioner requires 3 block types.\n"
292 << "It is sub preconditioner for the BiharmonicPreconditioner.\n";
293 throw OomphLibError(
295 }
296#endif
297
298 // Data type indicating which blocks from the preconditioner matrix we want
300
301 // boolean indicating if we want the block or not, stored for readability.
302 // Initially this is set to true for all blocks. Later we select which
303 // blocks we do not want.
304 const bool want_block = true;
305 for (unsigned b_i = 0; b_i < n_block_types; b_i++)
306 {
307 for (unsigned b_j = 0; b_j < n_block_types; b_j++)
308 {
309 required_blocks[b_i][b_j].select_block(b_i, b_j, want_block);
310 }
311 }
312
313 // Which blocks do we not want?
315 {
316 required_blocks[1][2].do_not_want_block();
317 required_blocks[2][1].do_not_want_block();
318 }
319
320 // Get the preconditioner matrix as defined by required_blocks
322 this->get_concatenated_block(required_blocks);
323
324 // setup the preconditioner
328
329 // preconditioner_matrix will now go out of scope (and is destroyed).
330 }
331
332
333 //============================================================================
334 /// preconditioner solve for the exact sub biharmonic preconditioner
335 //============================================================================
337 const DoubleVector& r, DoubleVector& z)
338 {
339 // vectors for use within the sub preconditioner
342
343 // get the sub r vector
345
346 // solve the preconditioner
348
349 // return the sub z vector to the master z vector
351 }
352
353
354 //============================================================================
355 /// setup for the inexact sub biharmonic preconditioner
356 //============================================================================
358 {
359 // clean up memory first
360 this->clean_up_memory();
361
362 // setup
363 this->block_setup();
364
365 // Number of block types
366 unsigned n_block_types = this->nblock_types();
367
368 // paranoid check for number of blocks
369#ifdef PARANOID
370 if (n_block_types != 3)
371 {
372 std::ostringstream error_message;
373 error_message
374 << "This preconditioner requires 3 block types.\n"
375 << "It is sub preconditioner for the BiharmonicPreconditioner.\n";
376 throw OomphLibError(
378 }
379#endif
380
381 // required blocks
383 required_blocks(0, 0) = true;
384 required_blocks(0, 1) = true;
385 required_blocks(1, 0) = true;
386 required_blocks(1, 1) = true;
387 required_blocks(0, 2) = true;
388 required_blocks(2, 0) = true;
389 required_blocks(2, 2) = true;
390
391 // Matrix of block matrix pointers
393
394 // get the blocks
395 this->get_blocks(required_blocks, Matrix_of_block_pointers);
396
397 // lump the matrix J_11
401
402 delete Matrix_of_block_pointers(1, 1);
403 Matrix_of_block_pointers(1, 1) = 0;
404
405 // lump the matrix J_22
409 delete Matrix_of_block_pointers(2, 2);
410 Matrix_of_block_pointers(2, 2) = 0;
411
412 // compute the schur complement
414
415 // create the preconditioner for the S00 Schur complement linear system
416 if (Use_amg)
417 {
418#ifdef OOMPH_HAS_HYPRE
419 // Use Hypre Boomer AMG
423#else
424 std::ostringstream error_message;
425 error_message << "Request AMG solver but oomph-lib does not have HYPRE";
426 throw OomphLibError(
428#endif
429 }
430 else
431 {
434 }
435
436 // setup the preconditioner
438
439 // clean up
440 delete S_00_pt;
441 S_00_pt = 0;
442 }
443
444 //============================================================================
445 /// computes the schur complement for the inexact sub biharmonic
446 /// preconditioner
447 //============================================================================
449 {
450 // if required get pointers to the vector components of J01 and J10
451 int* J_01_row_start = 0;
452 int* J_01_column_index = 0;
453 double* J_01_value = 0;
454 int* J_10_row_start = 0;
455 int* J_10_column_index = 0;
456
457 // J_01 matrix
458 J_01_row_start = Matrix_of_block_pointers(0, 1)->row_start();
459 J_01_column_index = Matrix_of_block_pointers(0, 1)->column_index();
460 J_01_value = Matrix_of_block_pointers(0, 1)->value();
461
462 // J_10 matrix
463 J_10_row_start = Matrix_of_block_pointers(1, 0)->row_start();
464 J_10_column_index = Matrix_of_block_pointers(1, 0)->column_index();
465
466 // if required get pointers to the vector components of J01 and J10
467 int* J_02_row_start = 0;
468 int* J_02_column_index = 0;
469 double* J_02_value = 0;
470 int* J_20_row_start = 0;
471 int* J_20_column_index = 0;
472
473 // J_02 matrix
474 J_02_row_start = Matrix_of_block_pointers(0, 2)->row_start();
475 J_02_column_index = Matrix_of_block_pointers(0, 2)->column_index();
476 J_02_value = Matrix_of_block_pointers(0, 2)->value();
477
478 // J_20 matrix
479 J_20_row_start = Matrix_of_block_pointers(2, 0)->row_start();
480 J_20_column_index = Matrix_of_block_pointers(2, 0)->column_index();
481
482 // get the inverse lumped vector of J_11 if required
483 double* J_11_lumped_and_inverted = 0;
485 Lumped_J_11_preconditioner_pt->inverse_lumped_vector_pt();
486
487 // get the inverse lumped vector of J_22 if required
488 double* J_22_lumped_and_inverted = 0;
490 Lumped_J_22_preconditioner_pt->inverse_lumped_vector_pt();
491
492 // size of J00 matrix (and S00 matrix)
493 unsigned J_00_nrow = Matrix_of_block_pointers(0, 0)->nrow();
494
495 // vectors for the schur complement
499
500 // number of elements in the x-dimension of the mesh
501 unsigned n_element_x =
503 dynamic_cast<BiharmonicPreconditioner*>(
505 ->bulk_element_mesh_pt())
506 ->nelement_in_dim(0);
507
508 // nnz in schur complement (initialised to zero)
509 unsigned S_00_nnz = 0;
510
511 // loop over columns of schur complement matrix
512 for (unsigned i = 0; i < J_00_nrow; i++)
513 {
514 // set column_start
516
517 // loop over rows in schur complement matrix
518 // the schur complement matrix has 5 well defined bands thus we only
519 // perform matrix-matrix multiplication for these bands
520 //
521 // where the diagonal band is 0 :
522 //
523 // band 1 : -2*n_element_x +/- 5
524 // 2 : -n_element_x +/- 3
525 // 3 : 0 +/- 3
526 // 4 : n_element_x +/- 3
527 // 5 : 2*n_element_x +/- 5
528 //
529 // regardless of the type or combination of boundary conditions applied
530
531 // Vector for postion of the bands in S_00
533
534 // compute the minimum and maximum positions of each band in terms of
535 // row number for column j
536 // note : static_cast used because max and min don't work on unsigned
537 band_position[0].first =
538 std::max(0, static_cast<int>(i - n_element_x * 2 - 5));
539 band_position[0].second =
540 std::max(0,
541 std::min(static_cast<int>(J_00_nrow - 1),
542 static_cast<int>(i - n_element_x * 2 + 5)));
543 band_position[1].first =
544 std::max(band_position[0].second + 1,
545 std::max(0, static_cast<int>(i - n_element_x - 3)));
546 band_position[1].second =
547 std::max(0,
548 std::min(static_cast<int>(J_00_nrow - 1),
549 static_cast<int>(i - n_element_x + 3)));
550 band_position[2].first = std::max(band_position[1].second + 1,
551 std::max(0, static_cast<int>(i - 3)));
552 band_position[2].second = std::max(
553 0, std::min(static_cast<int>(J_00_nrow - 1), static_cast<int>(i + 3)));
554 band_position[3].first =
555 std::max(band_position[2].second + 1,
556 std::max(0, static_cast<int>(i + n_element_x - 3)));
557 band_position[3].second =
558 std::max(0,
559 std::min(static_cast<int>(J_00_nrow - 1),
560 static_cast<int>(i + n_element_x + 3)));
561 band_position[4].first =
562 std::max(band_position[3].second + 1,
563 std::max(0, static_cast<int>(i + n_element_x * 2 - 5)));
564 band_position[4].second =
565 std::max(0,
566 std::min(static_cast<int>(J_00_nrow - 1),
567 static_cast<int>(i + n_element_x * 2 + 5)));
568
569 // number of bands
570 unsigned n_band = 5;
571
572 // loop over the bands
573 for (unsigned b = 0; b < n_band; b++)
574 {
575 // loop over the rows in band b
576 for (unsigned j = static_cast<unsigned>(band_position[b].first);
578 j++)
579 {
580 ;
581
582 // temporary value for the computation of S00(i,j)
583 double temp_value = Matrix_of_block_pointers(0, 0)->operator()(i, j);
584
585 // iterate through non-zero entries of column j of A_10
586 for (int k = J_01_row_start[i]; k < J_01_row_start[i + 1]; k++)
587 {
589 static_cast<int>(j) &&
590 static_cast<int>(j) <=
592 1])
593 {
595 Matrix_of_block_pointers(1, 0)->operator()(
598 }
599 }
600
601 // next compute contribution for A_02*lumped(A_22)'*A_20
602
603 // iterate through non-zero entries of column j of A_10
604 for (int k = J_02_row_start[i]; k < J_02_row_start[i + 1]; k++)
605 {
607 static_cast<int>(j) &&
608 static_cast<int>(j) <=
610 1])
611 {
613 Matrix_of_block_pointers(2, 0)->operator()(
616 }
617 }
618
619 // add element to schur complement matrix S00
620 if (temp_value != 0.0)
621 {
622 S_00_nnz++;
623 S_00_value.push_back(temp_value);
624 S_00_column_index.push_back(j);
625 }
626 }
627 }
628 }
629
630 // last entry of s00 column start
632
633 // build the schur complement S00
635 J_00_nrow,
639
640 // replace block J01 with J01*lumped(J11)' (if J11 can be lumped)
641 unsigned J_01_nnz = Matrix_of_block_pointers(0, 1)->nnz();
642 for (unsigned i = 0; i < J_01_nnz; i++)
643 {
645 }
646
647 // replace block J_02 with J_02*lumped(J_22)' (if J22 can be lumped)
648 unsigned J_02_nnz = Matrix_of_block_pointers(0, 2)->nnz();
649 for (unsigned i = 0; i < J_02_nnz; i++)
650 {
652 }
653 }
654
655
656 //============================================================================
657 /// preconditioner solve for the inexact sub biharmonic preconditioner
658 //============================================================================
660 const DoubleVector& r, DoubleVector& z)
661 {
662 // get the block vectors
665
666 // r_0 = r_0 - J_01 * lumped(J_11)'*r_1 - J_02 * lumped(J_22)'*r_2
667 // Remember that J_01 has already been premultiplied by lumped(J_11)
669 Matrix_of_block_pointers(0, 1)->multiply(block_r[1], temp);
670 block_r[0] -= temp;
671 temp.clear();
672 Matrix_of_block_pointers(0, 2)->multiply(block_r[2], temp);
673 block_r[0] -= temp;
674
675 // apply the inexact preconditioner
676 temp.clear();
679
680 // solve: lumped(J_11) x_1 = r_1 - J_10 x_0 for x_1
681 // remember temp contains r_0 (...or z_0)
683 Matrix_of_block_pointers(1, 0)->multiply(temp, temp2);
684 block_r[1] -= temp2;
686 Lumped_J_11_preconditioner_pt->preconditioner_solve(block_r[1], z_1);
688
689 // solve: lumped(J_22) x_2 = r_2 - J_20 x_0 for x_2
690 // remember temp contains r_0 (...or z_0)
691 temp2.clear();
692 Matrix_of_block_pointers(2, 0)->multiply(temp, temp2);
693 block_r[2] -= temp2;
695 Lumped_J_22_preconditioner_pt->preconditioner_solve(block_r[2], z_2);
697 }
698} // namespace oomph
cstr elem_len * i
Definition cfortran.h:603
Biharmonic Preconditioner - for two dimensional problems.
Preconditioner * Hijacked_sub_block_preconditioner_pt
Preconditioner the diagonal block associated with hijacked elements.
Preconditioner * Sub_preconditioner_2_pt
Inexact Preconditioner Pointer.
void clean_up_memory()
Clean up memory (empty). Generic interface function.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
void setup()
Setup the preconditioner.
unsigned Preconditioner_type
preconditioner type
Mesh * Bulk_element_mesh_pt
the bulk element mesh pt
Preconditioner * Sub_preconditioner_1_pt
Exact Preconditioner Pointer.
void return_block_vector(const unsigned &n, const DoubleVector &b, DoubleVector &v) const
Takes the n-th block ordered vector, b, and copies its entries to the appropriate entries in the natu...
CRDoubleMatrix get_concatenated_block(const VectorMatrix< BlockSelector > &selected_block)
Returns a concatenation of the block matrices specified by the argument selected_block....
void get_blocks(DenseMatrix< bool > &required_blocks, DenseMatrix< CRDoubleMatrix * > &block_matrix_pt) const
Get all the block matrices required by the block preconditioner. Takes a pointer to a matrix of bools...
void get_block(const unsigned &i, const unsigned &j, CRDoubleMatrix &output_matrix, const bool &ignore_replacement_block=false) const
Put block (i,j) into output_matrix. This block accounts for any coarsening of dof types and any repla...
void get_block_vector(const unsigned &n, const DoubleVector &v, DoubleVector &b) const
Takes the naturally ordered vector, v and returns the n-th block vector, b. Here n is the block numbe...
BlockPreconditioner< CRDoubleMatrix > * master_block_preconditioner_pt() const
Access function to the master block preconditioner pt.
unsigned nblock_types() const
Return the number of block types.
void return_block_ordered_preconditioner_vector(const DoubleVector &w, DoubleVector &v) const
Takes the block ordered vector, w, and reorders it in natural order. Reordered vector is returned in ...
void get_block_vectors(const Vector< unsigned > &block_vec_number, const DoubleVector &v, Vector< DoubleVector > &s) const
Takes the naturally ordered vector and rearranges it into a vector of sub vectors corresponding to th...
CRDoubleMatrix * matrix_pt() const
Access function to matrix_pt. If this is the master then cast the matrix pointer to MATRIX*,...
const LinearAlgebraDistribution * block_distribution_pt(const unsigned &b) const
Access function to the block distributions (const version).
virtual void block_setup()
Determine the size of the matrix blocks and setup the lookup schemes relating the global degrees of f...
void set_mesh(const unsigned &i, const Mesh *const mesh_pt, const bool &allow_multiple_element_type_in_mesh=false)
Set the i-th mesh for this block preconditioner. Note: The method set_nmesh(...) must be called befor...
void get_block_ordered_preconditioner_vector(const DoubleVector &v, DoubleVector &w)
Given the naturally ordered vector, v, return the vector rearranged in block order in w....
A class for compressed row matrices. This is a distributable object.
Definition matrices.h:888
A vector in the mathematical sense, initially developed for linear algebra type applications....
void initialise(const double &v)
initialise the whole vector with value v
void clear()
wipes the DoubleVector
Sub Biharmonic Preconditioner - an exact preconditioner for the 3x3 top left hand corner sub block ma...
void clean_up_memory()
delete the subsidiary preconditioner pointer
bool Retain_all_blocks
Boolean indicating that all blocks are to be retained (defaults to false)
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
An Preconditioner class using the suite of Hypre preconditioners to allow.
SubBiharmonic Preconditioner - an inexact preconditioner for the 3x3 top left hand corner sub block m...
DenseMatrix< CRDoubleMatrix * > Matrix_of_block_pointers
void compute_inexact_schur_complement()
Computes the inexact schur complement of the block J_00 using lumping as an approximate inverse of bl...
Preconditioner * S_00_preconditioner_pt
Pointer to the S00 Schur Complement preconditioner.
unsigned Use_amg
booean indicating whether (Hypre BoomerAMG) AMG should be used to solve the S00 subsidiary linear sys...
MatrixBasedLumpedPreconditioner< CRDoubleMatrix > * Lumped_J_22_preconditioner_pt
Preconditioner for storing the lumped J_22 matrix.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
MatrixBasedLumpedPreconditioner< CRDoubleMatrix > * Lumped_J_11_preconditioner_pt
Preconditioner for storing the lumped J_11 matrix.
Matrix-based diagonal preconditioner.
An OomphLibError object which should be thrown when an run-time error is encountered....
virtual void setup(DoubleMatrixBase *matrix_pt)
Setup the preconditioner: store the matrix pointer and the communicator pointer then call preconditio...
virtual void preconditioner_solve(const DoubleVector &r, DoubleVector &z)=0
Apply the preconditioner. Pure virtual generic interface function. This method should apply the preco...
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
double AMG_jacobi_damping
jacobi damping – hierher not used 0.1
unsigned AMG_smoother
smoother type - Gauss Seidel: 1
void set_defaults(HyprePreconditioner *hypre_prec_pt)
set the defaults
unsigned AMG_coarsening
amg coarsening strategy: classical Ruge Stueben: 1
double AMG_strength
amg strength parameter: 0.25 – optimal for 2d
Preconditioner * create_exact_preconditioner()
Factory function to create suitable exact preconditioner.
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...