fsi_preconditioners.h
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-2023 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 #ifndef OOMPH_FSI_PRECONDITIONERS_HEADER
27 #define OOMPH_FSI_PRECONDITIONERS_HEADER
28 
29 
30 #include "../navier_stokes/navier_stokes_preconditioners.h"
31 
32 namespace oomph
33 {
34  /// ////////////////////////////////////////////////////////////////////////////
35  /// ////////////////////////////////////////////////////////////////////////////
36  /// ////////////////////////////////////////////////////////////////////////////
37 
38 
39  //============================================================================
40  /// FSI preconditioner. This extracts upper/lower triangular
41  /// blocks in the 3x3 overall block matrix structure arising from
42  /// the monolithic discretisation of FSI problems with algebraic
43  /// node updates. Dofs are decomposed into fluid velocity, pressure
44  /// and solid unknowns. NavierStokesSchurComplementPreconditioner is used
45  /// as the inexact solver for the fluid block; SuperLU (in
46  /// its incarnation as an "exact" preconditioner) is used for
47  /// the solid block. By default we retain the fluid on solid off
48  /// diagonal blocks.
49  //=============================================================================
50  class FSIPreconditioner : public BlockPreconditioner<CRDoubleMatrix>
51  {
52  public:
53  /// Constructor: By default use block triangular form with retained
54  /// fluid on solid terms. A problem pointer is required for the underlying
55  /// NavierStokesSchurComplementPreconditioner.
56  FSIPreconditioner(Problem* problem_pt)
57  {
58  // set the mesh pointers
59  this->set_nmesh(2);
61  Wall_mesh_pt = 0;
62 
63  // Initially assume that there are no multiple element types in the
64  // meshes.
67 
68  // Default setting: Fluid onto solid as it this was shown to be
69  // marginally faster than solid onto fluid; see Heil CMAME 193 (2004)
72 
73  // Create the Navier Stokes Schur complement preconditioner
75  new NavierStokesSchurComplementPreconditioner(problem_pt);
76 
77  // Create the Solid preconditioner
78  Solid_preconditioner_pt = new SuperLUPreconditioner;
79 
80  // Preconditioner hasn't been set up yet.
82 
83  // Create the matrix vector product operators
84  Matrix_vector_product_0_1_pt = new MatrixVectorProduct;
85  Matrix_vector_product_1_0_pt = new MatrixVectorProduct;
86 
87  // set Doc_time to false
88  Doc_time = false;
89  }
90 
91 
92  /// Destructor: Clean up.
94  {
95  // Delete the Navier-Stokes preconditioner (inexact solver)
97 
98  // Delete the solid preconditioner (inexact solver)
100 
101  // delete the matrix vector product operators
104  }
105 
106 
107  /// Broken copy constructor
109 
110 
111  /// Broken assignment operator
112  // Commented out broken assignment operator because this can lead to a
113  // conflict warning when used in the virtual inheritence hierarchy.
114  // Essentially the compiler doesn't realise that two separate
115  // implementations of the broken function are the same and so, quite
116  // rightly, it shouts.
117  /*void operator=(const FSIPreconditioner&) =
118  delete;*/
119 
120  /// Set solid preconditioner (deletes existing one)
122  {
123  // Kill existing one
124  if (Solid_preconditioner_pt != 0)
125  {
127  }
129  }
130 
131  /// Read-only access to solid preconditoner (use set_... to set it)
132  Preconditioner* solid_preconditioner_pt() const
133  {
135  }
136 
137 
138  /// Switch to block-diagonal preconditioner
140  {
143  }
144 
145  /// Switch to block-triangular preconditioner in which
146  /// action of fluid dofs onto solid equations is retained
148  {
151  }
152 
153  /// Switch to block-triangular preconditioner in which
154  /// action of solid dofs onto fluid equations is retained
156  {
159  }
160 
161  /// Setter function for the mesh containing the
162  /// block-preconditionable Navier-Stokes elements. The optional argument
163  /// indicates if there are more than one type of elements in same mesh.
165  Mesh* mesh_pt,
166  const bool& allow_multiple_element_type_in_navier_stokes_mesh = false)
167  {
168  // Store the mesh pointer.
169  Navier_stokes_mesh_pt = mesh_pt;
170 
171  // Are there multiple element types in the Navier-Stokes mesh?
173  allow_multiple_element_type_in_navier_stokes_mesh;
174  }
175 
176  /// Setter function for the mesh containing the
177  /// block-preconditionable FSI solid elements. The optional argument
178  /// indicates if there are more than one type of elements in the same mesh.
180  Mesh* mesh_pt,
181  const bool& allow_multiple_element_type_in_wall_mesh = false)
182  {
183  // Store the mesh pointer
184  Wall_mesh_pt = mesh_pt;
185 
186  // Are there multiple element types in the wall mesh?
188  allow_multiple_element_type_in_wall_mesh;
189  }
190 
191  /// Setup the preconditioner
192  void setup();
193 
194  /// Apply preconditioner to r
195  void preconditioner_solve(const DoubleVector& r, DoubleVector& z);
196 
197  /// Access function to the Navier Stokes preconditioner (inexact solver)
198  NavierStokesSchurComplementPreconditioner* navier_stokes_preconditioner_pt()
199  const
200  {
202  }
203 
204  /// Enable documentation of time
206  {
207  Doc_time = true;
208  }
209 
210  /// Disable documentation of time
212  {
213  Doc_time = false;
214  }
215 
216 
217  private:
218  /// Pointer the Navier Stokes preconditioner (inexact solver)
219  NavierStokesSchurComplementPreconditioner* Navier_stokes_preconditioner_pt;
220 
221  /// Pointer to the solid preconditioner (inexact solver)
222  Preconditioner* Solid_preconditioner_pt;
223 
224  /// Pointer to fluid/solid interaction matrix
225  MatrixVectorProduct* Matrix_vector_product_0_1_pt;
226 
227  /// Pointer to solid/fluid solid interaction matrix
228  MatrixVectorProduct* Matrix_vector_product_1_0_pt;
229 
230  /// Boolean indicating the preconditioner has been set up
232 
233  /// Boolean flag used to indicate that the solid onto fluid
234  /// interaction terms are to be retained
236 
237  /// Boolean flag used to indicate that the fluid onto solid
238  /// interaction terms are to be retained
240 
241  /// Set Doc_time to true for outputting results of timings
242  bool Doc_time;
243 
244  /// Pointer to the navier stokes mesh
246 
247  /// pointer to the solid mesh
249 
250  /// Flag to indicate if there are multiple element types in the
251  /// Navier-Stokes mesh.
253 
254  // Flag to indicate if there are multiple element types in the Wall mesh.
256  };
257 
258 
259  /// ///////////////////////////////////////////////////////////////////////////
260  /// ///////////////////////////////////////////////////////////////////////////
261  // FSI preconditioner member functions
262  /// ///////////////////////////////////////////////////////////////////////////
263  /// ///////////////////////////////////////////////////////////////////////////
264 
265 
266  //=============================================================================
267  /// Setup the preconditioner. Note: Matrix must be a CRDoubleMatrix.
268  //=============================================================================
270  {
271  // check the meshes have been set
272 #ifdef PARANOID
273  if (Navier_stokes_mesh_pt == 0)
274  {
275  std::ostringstream error_message;
276  error_message << "Pointer to fluid mesh hasn't been set!\n";
277  throw OomphLibError(
278  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
279  }
280  if (Wall_mesh_pt == 0)
281  {
282  std::ostringstream error_message;
283  error_message << "Pointer to solid mesh hasn't been set!\n";
284  throw OomphLibError(
285  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
286  }
287 #endif
288 
289  // setup the meshes
290  this->set_mesh(0,
294 
295  // get the number of fluid dofs from teh first element in the mesh
296  unsigned n_fluid_dof = this->ndof_types_in_mesh(0);
297  unsigned n_dof = n_fluid_dof + this->ndof_types_in_mesh(1);
298 
299  // this fsi preconditioner has two types of DOF fluid dofs and solid dofs
300  Vector<unsigned> dof_to_block_map(n_dof, 0);
301  for (unsigned i = n_fluid_dof; i < n_dof; i++)
302  {
303  dof_to_block_map[i] = 1;
304  }
305 
306  // Call block setup for this preconditioner
307  this->block_setup(dof_to_block_map);
308 
309  // Block mapping for the subsidiary Navier Stokes preconditioner:
310  // blocks 0 and 1 in the FSI preconditioner are also blocks 0 and 1
311  // in the subsidiary Navier Stokes one.
312  Vector<unsigned> ns_dof_lookup(n_fluid_dof);
313  for (unsigned i = 0; i < n_fluid_dof; i++)
314  {
315  ns_dof_lookup[i] = i;
316  }
317 
318  // Turn the Navier Stokes Schur complement preconditioner into a
319  // subsidiary preconditioner of this preconditioner
320  Navier_stokes_preconditioner_pt->turn_into_subsidiary_block_preconditioner(
321  this, ns_dof_lookup);
322 
323  // Setup the navier stokes preconditioner: Tell it about the
324  // Navier Stokes mesh and set it up.
325  Navier_stokes_preconditioner_pt->set_navier_stokes_mesh(
327  Navier_stokes_preconditioner_pt->setup(matrix_pt());
328 
329  // Extract the additional blocks we need for FSI:
330 
331  // Solid tangent stiffness matrix
332  CRDoubleMatrix block_matrix_1_1;
333  this->get_block(1, 1, block_matrix_1_1);
334 
335  // Setup the solid preconditioner (inexact solver)
336  double t_start = TimingHelpers::timer();
337  Solid_preconditioner_pt->setup(&block_matrix_1_1);
338  double t_end = TimingHelpers::timer();
339  block_matrix_1_1.clear();
340  double setup_time = t_end - t_start;
341 
342  // Solid on fluid terms (if needed)
344  {
345  CRDoubleMatrix block_matrix_0_1 = get_block(0, 1);
346  this->setup_matrix_vector_product(
347  Matrix_vector_product_0_1_pt, &block_matrix_0_1, 1);
348  }
349 
350  // Fluid on solid terms (if needed)
352  {
353  CRDoubleMatrix block_matrix_1_0 = get_block(1, 0);
354  this->setup_matrix_vector_product(
355  Matrix_vector_product_1_0_pt, &block_matrix_1_0, 0);
356  }
357 
358  // Output times
359  if (Doc_time)
360  {
361  oomph_info << "Solid sub-preconditioner setup time [sec]: " << setup_time
362  << "\n";
363  }
364 
365  // We're done (and we stored some data)
367  }
368 
369 
370  //======================================================================
371  /// Apply preconditioner to Vector r
372  //======================================================================
373  void FSIPreconditioner::preconditioner_solve(const DoubleVector& r,
374  DoubleVector& z)
375  {
376  // if z is not setup then give it the same distribution
377  if (!z.built())
378  {
379  z.build(r.distribution_pt(), 0.0);
380  }
381 
382  // Make copy of residual vector (to overcome const-ness
383  DoubleVector res(r);
384 
385 
386  // Retain off-diagonals that represent effect of solid on fluid
387  //-------------------------------------------------------------
389  {
390  // Working vectors
391  DoubleVector temp_solid_vec;
392  DoubleVector temp_fluid_vec;
393 
394  // Copy solid values from residual to temp_vec:
395  // Loop over all entries in the global vector (this one
396  // includes solid, velocity and pressure dofs in some random fashion)
397  get_block_vector(1, res, temp_solid_vec);
398 
399  // Solve solid system by back-substitution
400  // with LU-decomposed stiffness matrix
401  DoubleVector temp_solid_vec2;
402  Solid_preconditioner_pt->preconditioner_solve(temp_solid_vec,
403  temp_solid_vec2);
404  this->return_block_vector(1, temp_solid_vec2, z);
405 
406  // NOTE: temp_solid_vec now contains z_s = S^{-1} r_s
407 
408  // Multiply C_{us} by z_s
409  Matrix_vector_product_0_1_pt->multiply(temp_solid_vec2, temp_fluid_vec);
410  temp_solid_vec.clear();
411 
412  // Subtract from fluid residual vector for fluid solve
413  DoubleVector another_temp_vec;
414  this->get_block_vector(0, res, another_temp_vec);
415  another_temp_vec -= temp_fluid_vec;
416  this->return_block_vector(0, another_temp_vec, res);
417 
418  // now apply the navier stokes lsc preconditioner
419  Navier_stokes_preconditioner_pt->preconditioner_solve(res, z);
420  }
421 
422 
423  // Retain off-diagonals that represent effect of fluid on solid
424  //-------------------------------------------------------------
425  // (or diagonal preconditioner)
426  //-----------------------------
427  else
428  {
429  // Call fluid preconditioner for fluid block
430  Navier_stokes_preconditioner_pt->preconditioner_solve(res, z);
431 
432  // Working vectors
433  DoubleVector temp_solid_vec;
434 
435  // get the solid vector
436  get_block_vector(1, res, temp_solid_vec);
437 
438  // Do matrix vector products with fluid onto solid coupling matrices:
440  {
441  DoubleVector temp_fluid_vec;
442  get_block_vector(0, z, temp_fluid_vec);
443 
444  // Auxiliary vector to hold the matrix vector product of the
445  // fluid-onto-solid coupling matrices with the fluid solutions:
446  DoubleVector aux_vec;
447 
448  // Multiply C_{su} by z_u
449  Matrix_vector_product_1_0_pt->multiply(temp_fluid_vec, aux_vec);
450 
451  // ...and subtract from r_s:
452  temp_solid_vec -= aux_vec;
453  }
454 
455  // Solve solid system by back-substitution
456  // with LU-decomposed stiffness matrix
457  DoubleVector temp_solid_vec2;
458  Solid_preconditioner_pt->preconditioner_solve(temp_solid_vec,
459  temp_solid_vec2);
460 
461  // Now copy result_vec (i.e. z_s) back into the global vector z.
462  // Loop over all entries in the global results vector z:
463  return_block_vector(1, temp_solid_vec2, z);
464  }
465  }
466 
467 
468  /// ////////////////////////////////////////////////////////////////////////
469  /// ////////////////////////////////////////////////////////////////////////
470  /// ////////////////////////////////////////////////////////////////////////
471 
472 
473  //============================================================================
474  /// FSI preconditioner. This extracts upper/lower triangular
475  /// blocks in the 3x3 overall block matrix structure arising from
476  /// the monolithic discretisation of FSI problems with algebraic
477  /// node updates. Dofs are decomposed into fluid velocity, pressure
478  /// and solid unknowns. Blocks are then re-assembled into one global
479  /// matrix and solved with a direct solver (SuperLU in its incarnation
480  /// as an exact preconditioner). By default we retain the fluid on solid off
481  /// diagonal blocks.
482  //=============================================================================
483  template<typename MATRIX>
484  class SimpleFSIPreconditioner : public BlockPreconditioner<MATRIX>
485  {
486  public:
487  /// Constructor.
488  SimpleFSIPreconditioner() : BlockPreconditioner<MATRIX>()
489  {
490  // set the mesh pointers
492  Wall_mesh_pt = 0;
493  this->set_nmesh(2);
494 
495  // Default setting: Retain fluid on solid
498 
499  // Null the preconditioner pointer (inexact solver)
500  Preconditioner_pt = 0;
501 
502  // Initially assume that there are no multiple element types in
503  // the same mesh.
506  }
507 
508 
509  /// Destructor: Clean up
511  {
512  // Wiping preconditioner (inexact solver) wipes the stored
513  // LU decompositon
514  if (Preconditioner_pt != 0)
515  {
516  delete Preconditioner_pt;
517  Preconditioner_pt = 0;
518  }
519  }
520 
521 
522  /// Broken copy constructor
524 
525 
526  /// Broken assignment operator
527  /*void operator=(const SimpleFSIPreconditioner&) = delete;*/
528 
529  /// Setter function for the mesh containing the
530  /// block-preconditionable Navier-Stokes elements.
532  Mesh* mesh_pt,
533  const bool& allow_multiple_element_type_in_navier_stokes_mesh = false)
534  {
535  // Store the mesh pointer.
536  Navier_stokes_mesh_pt = mesh_pt;
537 
538  // Are there multiple elements in this mesh?
540  allow_multiple_element_type_in_navier_stokes_mesh;
541  }
542 
543  /// Setter function for the mesh containing the
544  /// block-preconditionable FSI solid elements.
546  Mesh* mesh_pt,
547  const bool& allow_multiple_element_type_in_wall_mesh = false)
548  {
549  // Store the mesh pointer
550  Wall_mesh_pt = mesh_pt;
551 
552  // Are the multiple elements in this mesh?
554  allow_multiple_element_type_in_wall_mesh;
555  }
556 
557  /// Setup the preconditioner
558  void setup();
559 
560  /// Apply preconditioner to r
561  void preconditioner_solve(const DoubleVector& r, DoubleVector& z);
562 
563  /// Switch to block-diagonal preconditioner
565  {
568  }
569 
570  /// Switch to block-triangular preconditioner in which
571  /// action of fluid dofs onto solid equations is retained
573  {
576  }
577 
578  /// Switch to block-triangular preconditioner in which
579  /// action of solid dofs onto fluid equations is retained
581  {
584  }
585 
586  private:
587  /// Preconditioner (inexact solver)
588  Preconditioner* Preconditioner_pt;
589 
590  /// Boolean flag used to indicate that the solid onto fluid
591  /// interaction terms are to be retained
593 
594  /// Boolean flag used to indicate that the fluid onto solid
595  /// interaction terms are to be retained
597 
598  /// Identify the required blocks: Here we only need
599  /// the momentum, gradient and divergence blocks of the
600  /// 2x2 block-structured fluid matrix, the 1x1 solid block
601  /// and the selected FSI-off diagonals.
602  virtual void identify_required_blocks(DenseMatrix<bool>& required_blocks);
603 
604  /// Pointer to the navier stokes mesh
606 
607  /// pointer to the solid mesh
609 
610  /// Flag for multiple element types in the Navier-Stokes mesh.
612 
613  /// Flag for multiple element types in the Wall mesh
615  };
616 
617 
618  /// /////////////////////////////////////////////////////////////////////
619  /// /////////////////////////////////////////////////////////////////////
620  // FSI preconditioner member functions
621  /// /////////////////////////////////////////////////////////////////////
622  /// /////////////////////////////////////////////////////////////////////
623 
624 
625  //===========================================================================
626  /// Identify the required blocks: Here we only need
627  /// the momentum, gradient and divergence blocks of the
628  /// 2x2 block-structured fluid matrix, the 1x1 solid block
629  /// and the selected FSI-off diagonals.
630  //===========================================================================
631  template<typename MATRIX>
633  DenseMatrix<bool>& required_blocks)
634  {
635  // find number of block types
636  unsigned n_dof = this->nblock_types();
637 
638  // Initialise all blocks to false
639  for (unsigned i = 0; i < n_dof; i++)
640  {
641  for (unsigned j = 0; j < n_dof; j++)
642  {
643  required_blocks(i, j) = false;
644  }
645  }
646 
647  // Fluid: Only need momentum, gradient and divergence blocks
648  required_blocks(0, 0) = true;
649  required_blocks(1, 0) = true;
650  required_blocks(0, 1) = true;
651 
652  // Always retain the solid block
653  required_blocks(2, 2) = true;
654 
655  // Switch on the required off-diagonals
656  if (Retain_solid_onto_fluid_terms)
657  {
658  required_blocks(0, 2) = true;
659  required_blocks(1, 2) = true;
660  }
661  if (Retain_fluid_onto_solid_terms)
662  {
663  required_blocks(2, 0) = true;
664  required_blocks(2, 1) = true;
665  if (Retain_solid_onto_fluid_terms)
666  {
667  std::ostringstream error_message;
668  error_message << "Can't retain all off-diagonal blocks!\n";
669  throw OomphLibError(error_message.str(),
670  OOMPH_CURRENT_FUNCTION,
671  OOMPH_EXCEPTION_LOCATION);
672  }
673  }
674  }
675 
676 
677  //=============================================================================
678  /// Setup the preconditioner: Copy the upper/lower triangular
679  /// block matrices back into a big matrix (with the entries
680  /// re-ordered relative to the original Jacobian matrix).
681  //=============================================================================
682  template<typename MATRIX>
684  {
685  // Clean up memory
686  if (Preconditioner_pt != 0)
687  {
688  delete Preconditioner_pt;
689  Preconditioner_pt = 0;
690  }
691 #ifdef PARANOID
692  if (Navier_stokes_mesh_pt == 0)
693  {
694  std::ostringstream error_message;
695  error_message << "Pointer to fluid mesh hasn't been set!\n";
696  throw OomphLibError(
697  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
698  }
699  if (Wall_mesh_pt == 0)
700  {
701  std::ostringstream error_message;
702  error_message << "Pointer to solid mesh hasn't been set!\n";
703  throw OomphLibError(
704  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
705  }
706 #endif
707 
708  // setup the meshes
709  this->set_mesh(0,
710  Navier_stokes_mesh_pt,
711  Allow_multiple_element_type_in_navier_stokes_mesh);
712  this->set_mesh(1, Wall_mesh_pt, Allow_multiple_element_type_in_wall_mesh);
713 
714  // get the number of fluid dofs from the first element in the mesh
715  unsigned n_fluid_dof = this->ndof_types_in_mesh(0);
716  unsigned n_dof = n_fluid_dof + this->ndof_types_in_mesh(1);
717 
718  // this fsi preconditioner has two types of DOF fluid dofs and solid dofs
719  Vector<unsigned> dof_to_block_map(n_dof, 0);
720  dof_to_block_map[n_fluid_dof - 1] = 1; // pressure
721  for (unsigned i = n_fluid_dof; i < n_dof; i++) // solid
722  {
723  dof_to_block_map[i] = 2;
724  }
725 
726  // Set up the blocks look up schemes
727  this->block_setup(dof_to_block_map);
728 
729  // find number of block types
730  n_dof = this->nblock_types();
731 
732  // Create matrix that indicates which blocks are required
733  DenseMatrix<bool> required_blocks(n_dof, n_dof);
734 
735  // Identify required blocks
736  identify_required_blocks(required_blocks);
737 
738  VectorMatrix<BlockSelector> selected_blocks(n_dof, n_dof);
739 
740  for (unsigned dof_i = 0; dof_i < n_dof; dof_i++)
741  {
742  for (unsigned dof_j = 0; dof_j < n_dof; dof_j++)
743  {
744  selected_blocks[dof_i][dof_j].select_block(dof_i, dof_j, false, 0);
745 
746  if (required_blocks(dof_i, dof_j))
747  {
748  selected_blocks[dof_i][dof_j].want_block();
749  }
750  }
751  }
752 
753  CRDoubleMatrix P_matrix = this->get_concatenated_block(selected_blocks);
754 
755  // Setup preconditioner (i.e. inexact solver) -- does the LU decomposition
756  Preconditioner_pt = new SuperLUPreconditioner;
757  Preconditioner_pt->setup(&P_matrix);
758  }
759 
760 
761  //======================================================================
762  /// Apply preconditioner to Vector r
763  //======================================================================
764  template<typename MATRIX>
766  const DoubleVector& r, DoubleVector& z)
767  {
768  // create a temporary vector to hold the result of preconditioning
769  DoubleVector temp_vec;
770 
771  // get the reordered vector
772  this->get_block_ordered_preconditioner_vector(r, temp_vec);
773 
774  // apply preconditioner to z and store in r
775  Preconditioner_pt->preconditioner_solve(temp_vec, temp_vec);
776 
777  // copy the solution back
778  this->return_block_ordered_preconditioner_vector(temp_vec, z);
779  }
780 
781 
782  /// ////////////////////////////////////////////////////////////////////////
783  /// ////////////////////////////////////////////////////////////////////////
784  /// ////////////////////////////////////////////////////////////////////////
785 
786 
787 } // namespace oomph
788 
789 #endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////...
void set_solid_preconditioner_pt(Preconditioner *solid_preconditioner_pt)
Broken assignment operator.
void use_block_triangular_version_with_solid_on_fluid()
Switch to block-triangular preconditioner in which action of solid dofs onto fluid equations is retai...
Mesh * Navier_stokes_mesh_pt
Pointer to the navier stokes mesh.
void enable_doc_time()
Enable documentation of time.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
bool Doc_time
Set Doc_time to true for outputting results of timings.
bool Allow_multiple_element_type_in_navier_stokes_mesh
Flag to indicate if there are multiple element types in the Navier-Stokes mesh.
MatrixVectorProduct * Matrix_vector_product_0_1_pt
Pointer to fluid/solid interaction matrix.
FSIPreconditioner(const FSIPreconditioner &)=delete
Broken copy constructor.
void set_navier_stokes_mesh(Mesh *mesh_pt, const bool &allow_multiple_element_type_in_navier_stokes_mesh=false)
Setter function for the mesh containing the block-preconditionable Navier-Stokes elements....
void set_wall_mesh(Mesh *mesh_pt, const bool &allow_multiple_element_type_in_wall_mesh=false)
Setter function for the mesh containing the block-preconditionable FSI solid elements....
~FSIPreconditioner()
Destructor: Clean up.
MatrixVectorProduct * Matrix_vector_product_1_0_pt
Pointer to solid/fluid solid interaction matrix.
NavierStokesSchurComplementPreconditioner * navier_stokes_preconditioner_pt() const
Access function to the Navier Stokes preconditioner (inexact solver)
void use_block_diagonal_version()
Switch to block-diagonal preconditioner.
void disable_doc_time()
Disable documentation of time.
Preconditioner * Solid_preconditioner_pt
Pointer to the solid preconditioner (inexact solver)
Preconditioner * solid_preconditioner_pt() const
Read-only access to solid preconditoner (use set_... to set it)
bool Retain_solid_onto_fluid_terms
Boolean flag used to indicate that the solid onto fluid interaction terms are to be retained.
void use_block_triangular_version_with_fluid_on_solid()
Switch to block-triangular preconditioner in which action of fluid dofs onto solid equations is retai...
bool Preconditioner_has_been_setup
Boolean indicating the preconditioner has been set up.
bool Retain_fluid_onto_solid_terms
Boolean flag used to indicate that the fluid onto solid interaction terms are to be retained.
void setup()
Setup the preconditioner.
NavierStokesSchurComplementPreconditioner * Navier_stokes_preconditioner_pt
Pointer the Navier Stokes preconditioner (inexact solver)
Mesh * Wall_mesh_pt
pointer to the solid mesh
FSIPreconditioner(Problem *problem_pt)
Constructor: By default use block triangular form with retained fluid on solid terms....
//////////////////////////////////////////////////////////////////////// ////////////////////////////...
bool Retain_fluid_onto_solid_terms
Boolean flag used to indicate that the fluid onto solid interaction terms are to be retained.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
void set_wall_mesh(Mesh *mesh_pt, const bool &allow_multiple_element_type_in_wall_mesh=false)
Setter function for the mesh containing the block-preconditionable FSI solid elements.
Mesh * Wall_mesh_pt
pointer to the solid mesh
bool Retain_solid_onto_fluid_terms
Boolean flag used to indicate that the solid onto fluid interaction terms are to be retained.
bool Allow_multiple_element_type_in_wall_mesh
Flag for multiple element types in the Wall mesh.
~SimpleFSIPreconditioner()
Destructor: Clean up.
void use_block_triangular_version_with_solid_on_fluid()
Switch to block-triangular preconditioner in which action of solid dofs onto fluid equations is retai...
SimpleFSIPreconditioner(const SimpleFSIPreconditioner &)=delete
Broken copy constructor.
Mesh * Navier_stokes_mesh_pt
Pointer to the navier stokes mesh.
bool Allow_multiple_element_type_in_navier_stokes_mesh
Flag for multiple element types in the Navier-Stokes mesh.
void use_block_diagonal_version()
Switch to block-diagonal preconditioner.
Preconditioner * Preconditioner_pt
Preconditioner (inexact solver)
void setup()
Setup the preconditioner.
void set_navier_stokes_mesh(Mesh *mesh_pt, const bool &allow_multiple_element_type_in_navier_stokes_mesh=false)
Broken assignment operator.
virtual void identify_required_blocks(DenseMatrix< bool > &required_blocks)
Identify the required blocks: Here we only need the momentum, gradient and divergence blocks of the 2...
void use_block_triangular_version_with_fluid_on_solid()
Switch to block-triangular preconditioner in which action of fluid dofs onto solid equations is retai...