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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 // Config header generated by autoconfig
31 #ifdef HAVE_CONFIG_H
32  #include <oomph-lib-config.h>
33 #endif
34 
35 
36 //oomph-lib includes
38 
39 
40 namespace oomph
41 {
42 
43 #ifdef OOMPH_HAS_HYPRE
44 
45 //=============================================================================
46 // defaults settings for the Hypre solver (AMG) when used as the approximate
47 // linear solver for the Schur complement (non-compound) linear subsidiary
48 // linear systems
49 //=============================================================================
50 namespace Biharmonic_schur_complement_Hypre_defaults
51 {
52 
53  /// smoother type - Gauss Seidel: 1
54  unsigned AMG_smoother = 1;
55 
56  /// amg coarsening strategy: classical Ruge Stueben: 1
57  unsigned AMG_coarsening = 1;
58 
59  /// number of V cycles: 2
60  unsigned N_cycle = 2;
61 
62  /// amg strength parameter: 0.25 -- optimal for 2d
63  double AMG_strength = 0.25;
64 
65  /// jacobi damping -- hierher not used 0.1
66  double AMG_jacobi_damping = 0.1;
67 
68  /// amg smoother iterations
70 
71  /// set the defaults
72  void set_defaults(HyprePreconditioner* hypre_prec_pt)
73  {
74 
75  // use AMG preconditioner
76  hypre_prec_pt->hypre_method() = HypreSolver::BoomerAMG;
77 
78  // Smoother types
79  hypre_prec_pt->amg_simple_smoother() = AMG_smoother;
80 
81  // jacobi damping
82 // hypre_prec_pt->amg_damping() = AMG_jacobi_damping;
83 
84  // coarsening stategy
85  hypre_prec_pt->amg_coarsening() = AMG_coarsening;
86 
87  oomph_info << "Current number of v cycles: "
88  << hypre_prec_pt->amg_iterations() << std::endl;
89 
90  // number of v-cycles
91  hypre_prec_pt->amg_iterations() = N_cycle;
92 
93  oomph_info << "Re-assigned number of v cycles: "
94  << hypre_prec_pt->amg_iterations() << std::endl;
95 
96  // strength parameter
97  hypre_prec_pt->amg_strength() = AMG_strength;
98 
99  // hierher new
100  oomph_info << "Current number of amg smoother iterations: "
101  << hypre_prec_pt->amg_smoother_iterations() << std::endl;
102 
104 
105  oomph_info << "Re-assigned number of amg smoother iterations: "
106  << hypre_prec_pt->amg_smoother_iterations() << std::endl;
107  }
108 }
109 #endif
110 
111 //===========================================================================
112 /// setup for the biharmonic preconditioner
113 //===========================================================================
115 {
116  // clean up
117  this->clean_up_memory();
118 
119  // paranoid check that teh bulk element mesh has been set
120 #ifdef PARANOID
121  if (Bulk_element_mesh_pt==0)
122  {
123  std::ostringstream error_message;
124  error_message
125  << "The bulk element mesh has not been passed to bulk_element_mesh_pt()";
126  throw OomphLibError(error_message.str(),
127  OOMPH_CURRENT_FUNCTION,
128  OOMPH_EXCEPTION_LOCATION);
129  }
130 #endif
131 
132  // setup the mesh
133  this->set_mesh(0,Bulk_element_mesh_pt);
134 
135  //setup the blocks look up schemes
136  this->block_setup();
137 
138  // determine whether this preconditioner has 4 or 5 block types and set
139  // Nblock_types if neccessary
140 // unsigned n_row = this->master_nrow();
141 // bool nblock_type_check = true;
142 // for (unsigned i = 0; i < n_row; i++)
143 // {
144 // if (this->block_number(i) == 4) { nblock_type_check = false; }
145 // }
146 // if (nblock_type_check) { Nblock_types = 4; }
147 //
148 
149  // check the preconditioner type is acceptable
150 #ifdef PARANOID
151  if (Preconditioner_type != 0 &&
152  Preconditioner_type != 1 &&
153  Preconditioner_type != 2 &&
154  Preconditioner_type != 3 )
155  {
156  std::ostringstream error_message;
157  error_message
158  << "Preconditioner_type must be equal to 0 (BBD exact), 1 (inexact BBD with LU),"
159  << " 2 (inexact BBD with AMG) or 3 (exact BD).";
160  throw OomphLibError(error_message.str(),
161  OOMPH_CURRENT_FUNCTION,
162  OOMPH_EXCEPTION_LOCATION);
163  }
164 #endif
165 
166  // create the preconditioners
167  bool use_amg=true;
168  bool retain_all_blocks=false;
169  switch(Preconditioner_type)
170  {
171  // Exact BBD
172  case 0:
173 
174  retain_all_blocks=false;
175  Sub_preconditioner_1_pt =
176  new ExactSubBiharmonicPreconditioner(this,retain_all_blocks);
177  Sub_preconditioner_2_pt = new SuperLUPreconditioner;
178 
179  oomph_info << "Using exact BBD\n";
180  break;
181 
182  // Inexact BBD with LU
183  case 1:
184 
185  use_amg = false;
186  Sub_preconditioner_1_pt =
187  new InexactSubBiharmonicPreconditioner(this,use_amg);
188  Sub_preconditioner_2_pt = new MatrixBasedDiagPreconditioner;
189  oomph_info << "Using inexact BBD with LU\n";
190  break;
191 
192 
193  // Inexact BBD with AMG
194  case 2:
195 
196  use_amg = true;
197  Sub_preconditioner_1_pt =
198  new InexactSubBiharmonicPreconditioner(this,use_amg);
199  Sub_preconditioner_2_pt = new MatrixBasedDiagPreconditioner;
200  oomph_info << "Using inexact BBD with AMG\n";
201  break;
202 
203  /// Exact BD
204  case 3:
205 
206  retain_all_blocks=true;
207  Sub_preconditioner_1_pt =
208  new ExactSubBiharmonicPreconditioner(this,retain_all_blocks);
209  Sub_preconditioner_2_pt = new SuperLUPreconditioner;
210 
211  oomph_info << "Using exact BD\n";
212  break;
213 
214  default:
215 
216  throw OomphLibError("Wrong type of preconditioner.",
217  OOMPH_CURRENT_FUNCTION,
218  OOMPH_EXCEPTION_LOCATION);
219  }
220 
221 
222  // setup sub preconditioner pt 1
223  Sub_preconditioner_1_pt->setup(matrix_pt());
224 
225  // get the matrix ans setup sub preconditioner pt 2
226  CRDoubleMatrix* j_33_pt = new CRDoubleMatrix;
227  this->get_block(3,3,*j_33_pt);
228  Sub_preconditioner_2_pt->setup(j_33_pt);
229  delete j_33_pt; j_33_pt = 0;
230 
231  // if the block preconditioner has 5 block types setup the preconditioner
232  // for the 5th block diagonal block (Matrix is also diagonal hence a diagonal
233  // preconditioner is sufficient in the exact biharmonic preconditioner case
234  // as well)
235  if (this->nblock_types() == 5)
236  {
237  // get the matrix for block J_33
238  CRDoubleMatrix* j_44_pt = new CRDoubleMatrix;
239  this->get_block(4,4,*j_44_pt);
240 
241  // setup the hijacked sub preconditioner
242  Hijacked_sub_block_preconditioner_pt = new MatrixBasedDiagPreconditioner;
243  Hijacked_sub_block_preconditioner_pt->setup(j_44_pt);
244  delete j_44_pt; j_44_pt = 0;
245  }
246 }
247 
248 
249 
250 //============================================================================
251 /// \short preconditioner solve for the biharmonic preconditioner
252 //============================================================================
254  const DoubleVector &r, DoubleVector &z)
255  {
256  // zero z
257  z.initialise(0.0);
258 
259  // solve sub preconditioner 1
260  Sub_preconditioner_1_pt->preconditioner_solve(r,z);
261 
262  // solve sub preconditioner 2
263  DoubleVector block_r;
264  get_block_vector(3,r,block_r);
265  DoubleVector block_z;
266  Sub_preconditioner_2_pt->preconditioner_solve(block_r,block_z);
267  return_block_vector(3,block_z,z);
268 
269  // solve the hijacked sub block preconditioner if required
270  if (this->nblock_types() == 5)
271  {
272  block_r.clear();
273  block_z.clear();
274  get_block_vector(4,r,block_r);
275  Hijacked_sub_block_preconditioner_pt->
276  preconditioner_solve(block_r,block_z);
277  return_block_vector(4,block_z,z);
278  }
279  }
280 
281 //============================================================================
282 /// setup for the exact sub biharmonic preconditioner
283 //============================================================================
285 {
286  // clean up memory first
287  this->clean_up_memory();
288 
289  // setup
290  this->block_setup();
291 
292  // Number of block types
293  unsigned n_block_types = this->nblock_types();
294 
295  // check for required number of blocks
296 #ifdef PARANOID
297  if (n_block_types != 3)
298  {
299  std::ostringstream error_message;
300  error_message
301  << "This preconditioner requires 3 block types.\n"
302  << "It is sub preconditioner for the BiharmonicPreconditioner.\n";
303  throw OomphLibError(error_message.str(),
304  OOMPH_CURRENT_FUNCTION,
305  OOMPH_EXCEPTION_LOCATION);
306  }
307 #endif
308 
309  // Data type indicating which blocks from the preconditioner matrix we want
310  VectorMatrix<BlockSelector> required_blocks(n_block_types,n_block_types);
311 
312  // boolean indicating if we want the block or not, stored for readability.
313  // Initially this is set to true for all blocks. Later we select which
314  // blocks we do not want.
315  const bool want_block = true;
316  for (unsigned b_i = 0; b_i < n_block_types; b_i++)
317  {
318  for (unsigned b_j = 0; b_j < n_block_types; b_j++)
319  {
320  required_blocks[b_i][b_j].select_block(b_i,b_j,want_block);
321  }
322  }
323 
324  // Which blocks do we not want?
325  if (!Retain_all_blocks)
326  {
327  required_blocks[1][2].do_not_want_block();
328  required_blocks[2][1].do_not_want_block();
329  }
330 
331  // Get the preconditioner matrix as defined by required_blocks
332  CRDoubleMatrix preconditioner_matrix
333  = this->get_concatenated_block(required_blocks);
334 
335  // setup the preconditioner
336  Sub_preconditioner_pt = new SuperLUPreconditioner;
337  Sub_preconditioner_pt->setup(&preconditioner_matrix);
338 
339  // preconditioner_matrix will now go out of scope (and is destroyed).
340 }
341 
342 
343 //============================================================================
344 /// \short preconditioner solve for the exact sub biharmonic preconditioner
345 //============================================================================
348 {
349  // vectors for use within the sub preconditioner
350  DoubleVector sub_r;
351  DoubleVector sub_z;
352 
353  // get the sub r vector
354  get_block_ordered_preconditioner_vector(r,sub_r);
355 
356  // solve the preconditioner
357  Sub_preconditioner_pt->preconditioner_solve(sub_r,sub_z);
358 
359  // return the sub z vector to the master z vector
360  return_block_ordered_preconditioner_vector(sub_z,z);
361  }
362 
363 
364 //============================================================================
365 /// setup for the inexact sub biharmonic preconditioner
366 //============================================================================
368 {
369  // clean up memory first
370  this->clean_up_memory();
371 
372  // setup
373  this->block_setup();
374 
375  // Number of block types
376  unsigned n_block_types = this->nblock_types();
377 
378  // paranoid check for number of blocks
379 #ifdef PARANOID
380  if (n_block_types != 3)
381  {
382  std::ostringstream error_message;
383  error_message
384  << "This preconditioner requires 3 block types.\n"
385  << "It is sub preconditioner for the BiharmonicPreconditioner.\n";
386  throw OomphLibError(error_message.str(),
387  OOMPH_CURRENT_FUNCTION,
388  OOMPH_EXCEPTION_LOCATION);
389  }
390 #endif
391 
392  // required blocks
393  DenseMatrix<bool> required_blocks(n_block_types,n_block_types,false);
394  required_blocks(0,0) = true;
395  required_blocks(0,1) = true;
396  required_blocks(1,0) = true;
397  required_blocks(1,1) = true;
398  required_blocks(0,2) = true;
399  required_blocks(2,0) = true;
400  required_blocks(2,2) = true;
401 
402  // Matrix of block matrix pointers
403  Matrix_of_block_pointers.resize(n_block_types,n_block_types,0);
404 
405  // get the blocks
406  this->get_blocks(required_blocks, Matrix_of_block_pointers);
407 
408  // lump the matrix J_11
409  Lumped_J_11_preconditioner_pt =
411  Lumped_J_11_preconditioner_pt->
412  setup(Matrix_of_block_pointers(1,1));
413 
414  delete Matrix_of_block_pointers(1,1);
415  Matrix_of_block_pointers(1,1) = 0;
416 
417  // lump the matrix J_22
418  Lumped_J_22_preconditioner_pt =
420  Lumped_J_22_preconditioner_pt->setup(Matrix_of_block_pointers(2,2));
421  delete Matrix_of_block_pointers(2,2);
422  Matrix_of_block_pointers(2,2) = 0;
423 
424  // compute the schur complement
425  compute_inexact_schur_complement();
426 
427  // create the preconditioner for the S00 Schur complement linear system
428  if (Use_amg)
429  {
430 #ifdef OOMPH_HAS_HYPRE
431  // Use Hypre Boomer AMG
432  S_00_preconditioner_pt = new HyprePreconditioner;
434  set_defaults(static_cast<HyprePreconditioner*>(S_00_preconditioner_pt));
435 #else
436  std::ostringstream error_message;
437  error_message
438  << "Request AMG solver but oomph-lib does not have HYPRE";
439  throw OomphLibError(error_message.str(),
440  OOMPH_CURRENT_FUNCTION,
441  OOMPH_EXCEPTION_LOCATION);
442 #endif
443  }
444  else
445  {
446  S_00_preconditioner_pt = new SuperLUPreconditioner;
447  }
448 
449  // setup the preconditioner
450  S_00_preconditioner_pt->setup(S_00_pt);
451 
452  // clean up
453  delete S_00_pt;
454  S_00_pt = 0;
455 }
456 
457 //============================================================================
458 /// \short computes the schur complement for the inexact sub biharmonic
459 /// preconditioner
460 //============================================================================
462 {
463 
464  // if required get pointers to the vector components of J01 and J10
465  int* J_01_row_start = 0;
466  int* J_01_column_index = 0;
467  double* J_01_value = 0;
468  int* J_10_row_start = 0;
469  int* J_10_column_index = 0;
470 
471  // J_01 matrix
472  J_01_row_start = Matrix_of_block_pointers(0,1)->row_start();
473  J_01_column_index = Matrix_of_block_pointers(0,1)->column_index();
474  J_01_value = Matrix_of_block_pointers(0,1)->value();
475 
476  // J_10 matrix
477  J_10_row_start = Matrix_of_block_pointers(1,0)->row_start();
478  J_10_column_index = Matrix_of_block_pointers(1,0)->column_index();
479 
480  // if required get pointers to the vector components of J01 and J10
481  int* J_02_row_start = 0;
482  int* J_02_column_index = 0;
483  double* J_02_value = 0;
484  int* J_20_row_start = 0;
485  int* J_20_column_index = 0;
486 
487  // J_02 matrix
488  J_02_row_start = Matrix_of_block_pointers(0,2)->row_start();
489  J_02_column_index = Matrix_of_block_pointers(0,2)->column_index();
490  J_02_value = Matrix_of_block_pointers(0,2)->value();
491 
492  // J_20 matrix
493  J_20_row_start = Matrix_of_block_pointers(2,0)->row_start();
494  J_20_column_index = Matrix_of_block_pointers(2,0)->column_index();
495 
496  // get the inverse lumped vector of J_11 if required
497  double* J_11_lumped_and_inverted = 0;
498  J_11_lumped_and_inverted =
499  Lumped_J_11_preconditioner_pt->inverse_lumped_vector_pt();
500 
501  // get the inverse lumped vector of J_22 if required
502  double* J_22_lumped_and_inverted = 0;
503  J_22_lumped_and_inverted =
504  Lumped_J_22_preconditioner_pt->inverse_lumped_vector_pt();
505 
506  // size of J00 matrix (and S00 matrix)
507  unsigned J_00_nrow = Matrix_of_block_pointers(0,0)->nrow();
508 
509  // vectors for the schur complement
510  Vector<int> S_00_row_start(J_00_nrow+1);
511  Vector<int> S_00_column_index;
512  Vector<double> S_00_value;
513 
514  // number of elements in the x-dimension of the mesh
515  unsigned n_element_x =
517  (dynamic_cast<BiharmonicPreconditioner* >
518  (this->master_block_preconditioner_pt())->bulk_element_mesh_pt())
519  ->nelement_in_dim(0);
520 
521  // nnz in schur complement (initialised to zero)
522  unsigned S_00_nnz = 0;
523 
524  // loop over columns of schur complement matrix
525  for (unsigned i = 0; i < J_00_nrow; i++)
526  {
527 
528  // set column_start
529  S_00_row_start[i] = S_00_nnz;
530 
531  // loop over rows in schur complement matrix
532  // the schur complement matrix has 5 well defined bands thus we only
533  // perform matrix-matrix multiplication for these bands
534  //
535  // where the diagonal band is 0 :
536  //
537  // band 1 : -2*n_element_x +/- 5
538  // 2 : -n_element_x +/- 3
539  // 3 : 0 +/- 3
540  // 4 : n_element_x +/- 3
541  // 5 : 2*n_element_x +/- 5
542  //
543  // regardless of the type or combination of boundary conditions applied
544 
545  // Vector for postion of the bands in S_00
546  Vector<std::pair<int, int> > band_position(5);
547 
548  // compute the minimum and maximum positions of each band in terms of
549  // row number for column j
550  // note : static_cast used because max and min don't work on unsigned
551  band_position[0].first=std::max(0,static_cast<int>(i-n_element_x*2-5));
552  band_position[0].second=
553  std::max(0,
554  std::min(static_cast<int>(J_00_nrow-1),
555  static_cast<int>(i-n_element_x*2+5)));
556  band_position[1].first=
557  std::max(band_position[0].second+1,
558  std::max(0,static_cast<int>(i-n_element_x-3)));
559  band_position[1].second=
560  std::max(0,std::min(static_cast<int>(J_00_nrow-1),
561  static_cast<int>(i-n_element_x+3)));
562  band_position[2].first=
563  std::max(band_position[1].second+1,std::max(0,static_cast<int>(i-3)));
564  band_position[2].second=
565  std::max(0,std::min(static_cast<int>(J_00_nrow-1),
566  static_cast<int>(i+3)));
567  band_position[3].first=
568  std::max(band_position[2].second+1,
569  std::max(0,static_cast<int>(i+n_element_x-3)));
570  band_position[3].second=
571  std::max(0,std::min(static_cast<int>(J_00_nrow-1),
572  static_cast<int>(i+n_element_x+3)));
573  band_position[4].first=
574  std::max(band_position[3].second+1,
575  std::max(0,static_cast<int>(i+n_element_x*2-5)));
576  band_position[4].second
577  =std::max(0,std::min(static_cast<int>(J_00_nrow-1),
578  static_cast<int>(i+n_element_x*2+5)));
579 
580  // number of bands
581  unsigned n_band = 5;
582 
583  // loop over the bands
584  for (unsigned b = 0; b < n_band; b++)
585  {
586 
587  // loop over the rows in band b
588  for (unsigned j = static_cast<unsigned>(band_position[b].first);
589  j <= static_cast<unsigned>(band_position[b].second);j++)
590  { ;
591 
592  // temporary value for the computation of S00(i,j)
593  double temp_value = Matrix_of_block_pointers(0,0)->operator()(i,j);
594 
595  // iterate through non-zero entries of column j of A_10
596  for (int k = J_01_row_start[i]; k < J_01_row_start[i+1]; k++)
597  {
598  if ( J_10_column_index[J_10_row_start[J_01_column_index[k]]] <=
599  static_cast<int>(j) && static_cast<int>(j) <=
600  J_10_column_index[J_10_row_start[J_01_column_index[k]+1]-1] )
601  {
602  temp_value -= J_01_value[k] * Matrix_of_block_pointers(1,0)
603  ->operator()(J_01_column_index[k],j)*
604  J_11_lumped_and_inverted[J_01_column_index[k]];
605  }
606  }
607 
608  // next compute contribution for A_02*lumped(A_22)'*A_20
609 
610  // iterate through non-zero entries of column j of A_10
611  for (int k = J_02_row_start[i]; k < J_02_row_start[i+1]; k++)
612  {
613  if ( J_20_column_index[J_20_row_start[J_02_column_index[k]]] <=
614  static_cast<int>(j) && static_cast<int>(j) <=
615  J_20_column_index[J_20_row_start[J_02_column_index[k]+1]-1] )
616  {
617  temp_value -= J_02_value[k] * Matrix_of_block_pointers(2,0)
618  ->operator()(J_02_column_index[k],j)*
619  J_22_lumped_and_inverted[J_02_column_index[k]];
620  }
621  }
622 
623  // add element to schur complement matrix S00
624  if (temp_value != 0.0)
625  {
626  S_00_nnz++;
627  S_00_value.push_back(temp_value);
628  S_00_column_index.push_back(j);
629  }
630  }
631  }
632  }
633 
634  // last entry of s00 column start
635  S_00_row_start[J_00_nrow] = S_00_nnz;
636 
637  // build the schur complement S00
638  S_00_pt = new CRDoubleMatrix(this->block_distribution_pt(0),J_00_nrow,
639  S_00_value,S_00_column_index,S_00_row_start);
640 
641  // replace block J01 with J01*lumped(J11)' (if J11 can be lumped)
642  unsigned J_01_nnz = Matrix_of_block_pointers(0,1)->nnz();
643  for (unsigned i = 0; i < J_01_nnz; i++)
644  {
645  J_01_value[i] *= J_11_lumped_and_inverted[J_01_column_index[i]];
646  }
647 
648  // replace block J_02 with J_02*lumped(J_22)' (if J22 can be lumped)
649  unsigned J_02_nnz = Matrix_of_block_pointers(0,2)->nnz();
650  for (unsigned i = 0; i < J_02_nnz; i++)
651  {
652  J_02_value[i] *= J_22_lumped_and_inverted[J_02_column_index[i]];
653  }
654 }
655 
656 
657 
658 //============================================================================
659 /// \short preconditioner solve for the inexact sub biharmonic preconditioner
660 //============================================================================
663  {
664  // get the block vectors
665  Vector<DoubleVector> block_r(3);
666  get_block_vectors(r,block_r);
667 
668  // r_0 = r_0 - J_01 * lumped(J_11)'*r_1 - J_02 * lumped(J_22)'*r_2
669  // Remember that J_01 has already been premultiplied by lumped(J_11)
670  DoubleVector temp;
671  Matrix_of_block_pointers(0,1)->multiply(block_r[1],temp);
672  block_r[0] -= temp;
673  temp.clear();
674  Matrix_of_block_pointers(0,2)->multiply(block_r[2],temp);
675  block_r[0] -= temp;
676 
677  // apply the inexact preconditioner
678  temp.clear();
679  S_00_preconditioner_pt->preconditioner_solve(block_r[0],temp);
680  return_block_vector(0,temp,z);
681 
682  // solve: lumped(J_11) x_1 = r_1 - J_10 x_0 for x_1
683  //remember temp contains r_0 (...or z_0)
684  DoubleVector temp2;
685  Matrix_of_block_pointers(1,0)->multiply(temp,temp2);
686  block_r[1] -= temp2;
687  DoubleVector z_1;
688  Lumped_J_11_preconditioner_pt->preconditioner_solve(block_r[1],z_1);
689  return_block_vector(1,z_1,z);
690 
691  // solve: lumped(J_22) x_2 = r_2 - J_20 x_0 for x_2
692  //remember temp contains r_0 (...or z_0)
693  temp2.clear();
694  Matrix_of_block_pointers(2,0)->multiply(temp,temp2);
695  block_r[2] -= temp2;
696  DoubleVector z_2;
697  Lumped_J_22_preconditioner_pt->preconditioner_solve(block_r[2],z_2);
698  return_block_vector(2,z_2,z);
699  }
700 }
double AMG_strength
amg strength parameter: 0.25 – optimal for 2d
void set_defaults(HyprePreconditioner *hypre_prec_pt)
set the defaults
unsigned & amg_simple_smoother()
Access function to AMG_simple_smoother flag.
Definition: hypre_solver.h:888
unsigned & amg_iterations()
Return function for Max_iter.
Definition: hypre_solver.h:878
void clear()
wipes the DoubleVector
void compute_inexact_schur_complement()
Computes the inexact schur complement of the block J_00 using lumping as an approximate inverse of bl...
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
cstr elem_len * i
Definition: cfortran.h:607
A two dimensional Hermite bicubic element quadrilateral mesh for a topologically rectangular domain...
void setup()
Setup the preconditioner (store diagonal) from the fully assembled matrix.
unsigned AMG_smoother
smoother type - Gauss Seidel: 1
unsigned & amg_coarsening()
Access function to AMG_coarsening flag.
Definition: hypre_solver.h:910
OomphInfo oomph_info
void setup()
Function to set up a preconditioner for the linear system defined by matrix_pt. This function must be...
Matrix-based diagonal preconditioner.
void setup()
Setup terminate helper.
double AMG_jacobi_damping
jacobi damping – hierher not used 0.1
Sub Biharmonic Preconditioner - an exact preconditioner for the 3x3 top left hand corner sub block ma...
void initialise(const double &v)
initialise the whole vector with value v
unsigned & amg_smoother_iterations()
Access function to AMG_smoother_iterations.
Definition: hypre_solver.h:907
void setup()
Setup the preconditioner (store diagonal) from the fully assembled matrix. Problem pointer is ignored...
unsigned & hypre_method()
Access function to Hypre_method flag – specified via enumeration.
Definition: hypre_solver.h:862
void setup()
Setup the preconditioner.
An interface to allow SuperLU to be used as an (exact) Preconditioner.
unsigned AMG_coarsening
amg coarsening strategy: classical Ruge Stueben: 1
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
double & amg_strength()
Access function to AMG_strength.
Definition: hypre_solver.h:919
A vector in the mathematical sense, initially developed for linear algebra type applications. If MPI then this vector can be distributed - its distribution is described by the LinearAlgebraDistribution object at Distribution_pt. Data is stored in a C-style pointer vector (double*)
Definition: double_vector.h:61
SubBiharmonic Preconditioner - an inexact preconditioner for the 3x3 top left hand corner sub block m...
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
A class for compressed row matrices. This is a distributable object.
Definition: matrices.h:872
Biharmonic Preconditioner - for two dimensional problems.