multi_poisson_block_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-2022 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 // Header file with various simple block preconditioners written
27 // from scratch for "didactic" purposes, not necessarily to
28 // illustrate any particularly clever maths (though they work!)
29 
30 //Include guards
31 #ifndef OOMPH_SIMPLE_BLOCK_PRECONDITIONERS
32 #define OOMPH_SIMPLE_BLOCK_PRECONDITIONERS
33 
34 
35 // Config header generated by autoconfig
36 #ifdef HAVE_CONFIG_H
37 #include <oomph-lib-config.h>
38 #endif
39 
40 // oomph-lib includes
41 #include "generic.h"
42 
43 namespace oomph
44 {
45 
46 
47 //=========================start_of_diagonal_class=============================
50 //=============================================================================
51  template<typename MATRIX>
52  class Diagonal : public BlockPreconditioner<MATRIX>
53  {
54 
55  public :
56 
59  {
61  } // end_of_constructor
62 
63 
67  {
68  this->clean_up_my_memory();
69  }
70 
72  virtual void clean_up_my_memory();
73 
75  Diagonal(const Diagonal&)
76  {
77  BrokenCopy::broken_copy("Diagonal");
78  }
79 
81  void operator=(const Diagonal&)
82  {
83  BrokenCopy::broken_assign("Diagonal");
84  }
85 
86 
88  void setup();
89 
90  // Use the version in the Preconditioner base class for the alternative
91  // setup function that takes a matrix pointer as an argument.
93 
96 
97 
99  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
100  {
101  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
102  }
103 
104  private :
105 
109 
113 
114  };
115 
116  //=========================start_of_setup_for_simple========================
118  //============================================================================
119  template<typename MATRIX>
121  {
122  // clean the memory
123  this->clean_up_my_memory();
124 
125 
126 #ifdef PARANOID
127  if (Multi_poisson_mesh_pt == 0)
128  {
129  std::stringstream err;
130  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
131  throw OomphLibError(err.str(),
134  }
135 #endif
136 
137  // The preconditioner works with one mesh; set it!
138  this->set_nmesh(1);
139  this->set_mesh(0,Multi_poisson_mesh_pt);
140 
141  // Set up the generic block lookup scheme
142  this->block_setup();
143 
144  // Extract the number of blocks
145  unsigned nblock_types = this->nblock_types();
146 
147  // Create the subsidiary preconditioners
148  Diagonal_block_preconditioner_pt.resize(nblock_types);
149  for (unsigned i=0;i<nblock_types;i++)
150  {
151  Diagonal_block_preconditioner_pt[i] = new SuperLUPreconditioner;
152  }
153 
154  // Setup preconditioners
155  for (unsigned i=0;i<nblock_types;i++)
156  {
157  // Get block -- this makes a deep copy of the relevant entries in the
158  // full Jacobian (i.e. the matrix of the linear system we're
159  // actually trying to solve); we can do with this copy whatever
160  // we want...
162  this->get_block(i,i,block);
163 
164  // Set up preconditioner (i.e. lu-decompose the block)
165  Diagonal_block_preconditioner_pt[i]->setup(&block);
166 
167  // Done with this block now, so the diagonal block that we extracted
168  // above can go out of scope. Its LU decomposition (which is the only
169  // thing we need to apply the preconditioner in the preconditioner_solve(...)
170  // function) is retained in the associated sub-preconditioner/(in)exact
171  // solver(SuperLU).
172  }
173  }
174 
175 
176  //============================================================================
181  //============================================================================
182  template<typename MATRIX>
185  {
186  // Get number of blocks
187  unsigned nblock_types = this->nblock_types();
188 
189  // Split up rhs vector into sub-vectors, re-arranged to match
190  // the matrix blocks
191  Vector<DoubleVector> block_r;
192  this->get_block_vectors(r,block_r);
193 
194  // Solution of block solves
195  Vector<DoubleVector> block_z(nblock_types);
196  for (unsigned i = 0; i < nblock_types; i++)
197  {
198  Diagonal_block_preconditioner_pt[i]->preconditioner_solve(block_r[i],
199  block_z[i]);
200  }
201 
202  // Copy solution in block vectors block_z back to z
203  this->return_block_vectors(block_z,z);
204  }
205 
206  //=========================start_of_clean_up_for_simple=======================
208  //============================================================================
209  template<typename MATRIX>
211  {
212  // Delete diagonal preconditioners (approximate solvers)
213  unsigned n_block = Diagonal_block_preconditioner_pt.size();
214  for (unsigned i=0;i<n_block;i++)
215  {
216  if(Diagonal_block_preconditioner_pt[i]!=0)
217  {
218  delete Diagonal_block_preconditioner_pt[i];
219  Diagonal_block_preconditioner_pt[i]=0;
220  }
221  }
222  } // End of clean_up_my_memory function.
223 
224 
228 
229 
230 //=========================start_of_diagonal_class=============================
236 //=============================================================================
237  template<typename MATRIX>
238  class SimpleTwoDofOnly : public BlockPreconditioner<MATRIX>
239  {
240 
241  public :
242 
245  {
247  } // end_of_constructor
248 
249 
252  {
253  this->clean_up_my_memory();
254  }
255 
257  virtual void clean_up_my_memory();
258 
261  {
262  BrokenCopy::broken_copy("SimpleTwoDofOnly");
263  }
264 
267  {
268  BrokenCopy::broken_assign("SimpleTwoDofOnly");
269  }
270 
272  void setup();
273 
274  // Use the version in the Preconditioner base class for the alternative
275  // setup function that takes a matrix pointer as an argument.
276  using Preconditioner::setup;
277 
280 
282  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
283  {
284  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
285  }
286 
287  private :
288 
292 
296 
297  };
298 
299  //=========================start_of_setup_for_simple==========================
301  //============================================================================
302  template<typename MATRIX>
304  {
305  // clean the memory
306  this->clean_up_my_memory();
307 
308 #ifdef PARANOID
309  if (Multi_poisson_mesh_pt == 0)
310  {
311  std::stringstream err;
312  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
313  throw OomphLibError(err.str(),
316  }
317 #endif
318 
319  // The preconditioner works with one mesh; set it!
320  this->set_nmesh(1);
321  this->set_mesh(0,Multi_poisson_mesh_pt);
322 
323 #ifdef PARANOID
324  // This preconditioner only works for 2 dof types
325  unsigned n_dof_types = this->ndof_types();
326  if (n_dof_types!=2)
327  {
328  std::stringstream tmp;
329  tmp << "This preconditioner only works for problems with 2 dof types\n"
330  << "Yours has " << n_dof_types;
331  throw OomphLibError(tmp.str(),
334  }
335 #endif
336 
337  // Set up the generic block look up scheme
338  this->block_setup();
339 
340  // Extract the number of blocks.
341  unsigned nblock_types = this->nblock_types();
342 #ifdef PARANOID
343  if (nblock_types!=2)
344  {
345  std::stringstream tmp;
346  tmp << "There are supposed to be two block types.\n"
347  << "Yours has " << nblock_types;
348  throw OomphLibError(tmp.str(),
351  }
352 #endif
353 
354 
355  // Resize the storage for the diagonal blocks
356  Diagonal_block_preconditioner_pt.resize(nblock_types);
357 
358  // Create the subsidiary preconditioners
359  for (unsigned i=0;i<nblock_types;i++)
360  {
361  Diagonal_block_preconditioner_pt[i] = new SuperLUPreconditioner;
362  }
363 
364  // Setup preconditioners
365  for (unsigned i=0;i<nblock_types;i++)
366  {
367  // Get block -- this makes a copy of the relevant entries in the
368  // full Jacobian (i.e. the matrix of the linear system we're
369  // actually trying to solve); we can do with this copy whatever
370  // we want...
371  CRDoubleMatrix block = this->get_block(i,i);
372 
373  // Set up preconditioner (i.e. lu-decompose the block)
374  Diagonal_block_preconditioner_pt[i]->setup(&block);
375 
376  // Done with this block now, so the diagonal block that we extracted
377  // above can go out of scope. Its LU decomposition (which is the only
378  // thing we need to apply the preconditoner in the preconditoner_solve(...)
379  // function) is retained in the associated sub-preconditioner/(in)exact
380  // solver(SuperLU).
381  }
382  }
383 
384 
385  //============================================================================
390  //============================================================================
391  template<typename MATRIX>
394  {
395  // Get number of blocks
396  unsigned nblock_types = this->nblock_types();
397 
398  // Split up rhs vector into sub-vectors, re-arranged to match
399  // the matrix blocks
400  Vector<DoubleVector> block_r;
401  this->get_block_vectors(r,block_r);
402 
403  // Solution of block solves
404  Vector<DoubleVector> block_z(nblock_types);
405  for (unsigned i = 0; i < nblock_types; i++)
406  {
407  Diagonal_block_preconditioner_pt[i]->preconditioner_solve(block_r[i],
408  block_z[i]);
409  }
410 
411  // Copy solution in block vectors block_z back to z
412  this->return_block_vectors(block_z,z);
413  }
414 
415  //=========================start_of_clean_up==================================
417  //============================================================================
418  template<typename MATRIX>
420  {
421  // Delete diagonal preconditioners (approximate solvers)
422  unsigned n_block = Diagonal_block_preconditioner_pt.size();
423  for (unsigned i=0;i<n_block;i++)
424  {
425  if(Diagonal_block_preconditioner_pt[i]!=0)
426  {
427  delete Diagonal_block_preconditioner_pt[i];
428  Diagonal_block_preconditioner_pt[i]=0;
429  }
430  }
431  } // End of clean_up_my_memory function.
432 
433 
437 
438 
439 //=========================start_of_diagonal_class=============================
445 //=============================================================================
446  template<typename MATRIX>
447  class SimpleOneDofOnly : public BlockPreconditioner<MATRIX>
448  {
449 
450  public :
451 
454  {
457  } // end_of_constructor
458 
459 
462  {
463  this->clean_up_my_memory();
464  }
465 
467  virtual void clean_up_my_memory();
468 
471  {
472  BrokenCopy::broken_copy("SimpleOneDofOnly");
473  }
474 
477  {
478  BrokenCopy::broken_assign("SimpleOneDofOnly");
479  }
480 
481 
483  void setup();
484 
485  // Use the version in the Preconditioner base class for the alternative
486  // setup function that takes a matrix pointer as an argument.
487  using Preconditioner::setup;
488 
491 
493  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
494  {
495  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
496  }
497 
498  private :
499 
502 
506  };
507 
508  //=========================start_of_setup_for_simple==========================
510  //============================================================================
511  template<typename MATRIX>
513  {
514  // clean the memory
515  this->clean_up_my_memory();
516 
517 #ifdef PARANOID
518  if (Multi_poisson_mesh_pt == 0)
519  {
520  std::stringstream err;
521  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
522  throw OomphLibError(err.str(),
525  }
526 #endif
527 
528  // The preconditioner works with one mesh; set it!
529  this->set_nmesh(1);
530  this->set_mesh(0,Multi_poisson_mesh_pt);
531 
532 
533 #ifdef PARANOID
534  // This preconditioner only works for 1 dof type.
535  unsigned n_dof_types = this->ndof_types();
536  if (n_dof_types!=1)
537  {
538  std::stringstream tmp;
539  tmp << "This preconditioner only works for problems with 1 dof types\n"
540  << "Yours has " << n_dof_types;
541  throw OomphLibError(tmp.str(),
544  }
545 #endif
546 
547  // Set up the generic block look up scheme
548  this->block_setup();
549 
550 #ifdef PARANOID
551  const unsigned nblock_types = this->nblock_types();
552  if (nblock_types!=1)
553  {
554  std::stringstream tmp;
555  tmp << "There are supposed to be 1 block type.\n"
556  << "Yours has " << nblock_types;
557  throw OomphLibError(tmp.str(),
560  }
561 #endif
562 
563 
564  // Create the subsidiary preconditioner that actually does the
565  // work on the one-and-only block
566  Subsidiary_preconditioner_pt = new SuperLUPreconditioner;
567 
568  // Setup preconditioners
569  {
570  CRDoubleMatrix block = this->get_block(0,0);
571 
572  // Set up preconditioner (i.e. lu-decompose the block)
573  Subsidiary_preconditioner_pt->setup(&block);
574 
575  // Block can now go out of scope since subsidiaray preconditioner
576  // stores everything it needs (here the LU decomposition of the
577  // block).
578  }
579  }
580 
581 
582  //============================================================================
585  //============================================================================
586  template<typename MATRIX>
589  {
590  // Get the rhs into block order.
591  DoubleVector block_r;
592  this->get_block_vector(0,r,block_r);
593 
594  // Solution of block solve.
595  DoubleVector block_z;
596  Subsidiary_preconditioner_pt->preconditioner_solve(block_r, block_z);
597 
598  // Copy solution in block vector block_z back to z
599  this->return_block_vector(0,block_z,z);
600  }
601 
602  //=========================start_of_clean_up==================================
604  //============================================================================
605  template<typename MATRIX>
607  {
608  // Delete the preconditioner (approximate solvers)
609  if(Subsidiary_preconditioner_pt!=0)
610  {
611  delete Subsidiary_preconditioner_pt;
612  Subsidiary_preconditioner_pt=0;
613  }
614  } // End of clean_up_my_memory function.
615 
616 
620 
621 
622 //=========================start_of_diagonal_class=============================
631 //=============================================================================
632  template<typename MATRIX>
633  class CoarseTwoIntoOne : public BlockPreconditioner<MATRIX>
634  {
635 
636  public :
637 
640  {
643  } // end_of_constructor
644 
645 
648  {
649  this->clean_up_my_memory();
650  }
651 
653  virtual void clean_up_my_memory();
654 
657  {
658  BrokenCopy::broken_copy("CoarseTwoIntoOne");
659  }
660 
663  {
664  BrokenCopy::broken_assign("CoarseTwoIntoOne");
665  }
666 
667 
669  void setup();
670 
671  // This is put in to override the default behaviour of name hiding, which
672  // "hides", but does not override, base class functions with the same name
673  // as a derived class function even if the argument differ to allow for
674  // overloading. This is not a problem when using base class pointers.
675  using Preconditioner::setup;
676 
677 
683 
685  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
686  {
687  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
688  }
689 
690  private :
691 
694 
698  };
699 
700  //=========================start_of_setup_for_simple==========================
702  //============================================================================
703  template<typename MATRIX>
705  {
706  // clean the memory
707  this->clean_up_my_memory();
708 
709 #ifdef PARANOID
710  if (Multi_poisson_mesh_pt == 0)
711  {
712  std::stringstream err;
713  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
714  throw OomphLibError(err.str(),
717  }
718 #endif
719 
720  // The preconditioner works with one mesh; set it!
721  this->set_nmesh(1);
722  this->set_mesh(0,Multi_poisson_mesh_pt);
723 
724 
725 #ifdef PARANOID
726  // This preconditioner only works for 2 dof types
727  unsigned n_dof_types = this->ndof_types();
728 
729  // Output the number of dof types.
730  std::cout << "CoarseTwoIntoOne ndof_types: " << n_dof_types << std::endl;
731 
732  if (n_dof_types!=2)
733  {
734  std::stringstream tmp;
735  tmp << "This preconditioner only works for problems with 2 dof types\n"
736  << "Yours has " << n_dof_types;
737  throw OomphLibError(tmp.str(),
740  }
741 #endif
742 
743 
744  // Set up the generic block look up scheme
745  this->block_setup();
746 
747 
748 #ifdef PARANOID
749  unsigned n_block_types = this->nblock_types();
750 
751  std::cout << "CoarseTwoIntoOne nblock_types: "
752  << n_block_types << std::endl;
753 
754  if (n_block_types!=2)
755  {
756  std::stringstream tmp;
757  tmp << "There are supposed to be two block types.\n"
758  << "Yours has " << n_block_types;
759  throw OomphLibError(tmp.str(),
762  }
763 #endif
764 
765 
766  // Create the subsidiary preconditioners
767  SimpleOneDofOnly<CRDoubleMatrix>* block_prec_pt =
769  Subsidiary_preconditioner_pt = block_prec_pt;
770 
771  // Setup preconditioner
772  // We use a subsidiary block preconditioner which accepts only one DOF
773  // types. Since we have two DOF types, we must coarsen DOF types.
774  {
775  // Set mesh
776  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
777 
778  // This is the usual dof map between master's DOF type and subsidiary
779  // DOF types. In this case, the vector [0,1] tells the subsidiary block
780  // preconditioner that it's DOF type 0(1) is mapped to the master's DOF
781  // type 0(1).
782  Vector<unsigned>dof_map(2);
783  dof_map[0] = 0;
784  dof_map[1] = 1;
785 
786  // To coarsen DOF types, we have a 2D Vector.
787  // Size of the outer Vector is the number of subsidiary DOF types.
788  const unsigned n_sub_dof_types = 1;
789  Vector<Vector<unsigned> >doftype_coarsening(n_sub_dof_types);
790 
791  // The inner vector(s) tells the subsidiary block preconditioner which
792  // DOF types to coarsen into one. In this case the 0th inner vector is
793  // of size TWO with values [0,1], this tells the subsidiary block
794  // preconditioner that IT'S DOF type 0 and 1 is coarsened into
795  // DOF type 0.
796  doftype_coarsening[0].resize(2);
797  doftype_coarsening[0][0]=0;
798  doftype_coarsening[0][1]=1;
799 
800 
801  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,
802  dof_map,doftype_coarsening);
803 
804  // Set up block preconditioner. Note that because the subsidiary
805  // preconditioner is a block preconditioner itself it is given
806  // the pointer to the "full" matrix
807  block_prec_pt->setup(this->matrix_pt());
808  }
809  }
810 
811 
812  //============================================================================
817  //============================================================================
818  template<typename MATRIX>
821  {
822  // Call the subsidiary block preconditioner's preconditioner_solve(...)
823  // function. We do not need to return the solution to the vector z since
824  // this is handled by the subsidiary BLOCK preconditioner.
825  Subsidiary_preconditioner_pt->preconditioner_solve(r,z);
826  }
827 
828  //=========================start_of_clean_up_for_simple=======================
830  //============================================================================
831  template<typename MATRIX>
833  {
834  // Delete the subsidiary block preconditioner (approximate solver)
835  if(Subsidiary_preconditioner_pt!=0)
836  {
837  delete Subsidiary_preconditioner_pt;
838  Subsidiary_preconditioner_pt=0;
839  }
840  } // End of clean_up_my_memory function.
841 
842 
846 
847 
848 //=========================start_of_upper_triangular_class=====================
851 //=============================================================================
852  template<typename MATRIX>
853  class UpperTriangular : public BlockPreconditioner<MATRIX>
854  {
855 
856  public :
857 
860  {
862  }
863 
866  {
867  this->clean_up_my_memory();
868  }
869 
871  virtual void clean_up_my_memory();
872 
875  {
876  BrokenCopy::broken_copy("UpperTriangular");
877  }
878 
881  {
882  BrokenCopy::broken_assign("UpperTriangular");
883  }
884 
887 
889  void setup();
890 
891  // Use the version in the Preconditioner base class for the alternative
892  // setup function that takes a matrix pointer as an argument.
893  using Preconditioner::setup;
894 
896  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
897  {
898  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
899  }
900 
901  private:
902 
905 
909 
913 
914  };
915 
916  //========================start_of_setup_for_upper_triangular_class===========
918  //============================================================================
919  template<typename MATRIX>
921  {
922  // clean the memory
923  this->clean_up_my_memory();
924 
925 #ifdef PARANOID
926  if (Multi_poisson_mesh_pt == 0)
927  {
928  std::stringstream err;
929  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
930  throw OomphLibError(err.str(),
933  }
934 #endif
935 
936  // The preconditioner works with one mesh; set it!
937  this->set_nmesh(1);
938  this->set_mesh(0,Multi_poisson_mesh_pt);
939 
940  // Set up the block look up schemes
941  this->block_setup();
942 
943  // Number of block types
944  unsigned nblock_types = this->nblock_types();
945 
946  // Storage for the pointers to the off diagonal matrix vector products
947  // and the the subsidiary preconditioners (inexact solvers) for the diagonal
948  // blocks
949  Off_diagonal_matrix_vector_product_pt.resize(nblock_types,nblock_types,0);
950  Block_preconditioner_pt.resize(nblock_types);
951 
952  // Build the preconditioners and matrix vector products
953  for(unsigned i = 0; i < nblock_types; i++)
954  {
955  // Create the subsidiary preconditioners
956  Block_preconditioner_pt[i] = new SuperLUPreconditioner;
957 
958  // Put in braces so block matrix goes out of scope when done...
959  {
960  // Get block -- this makes a deep copy of the relevant entries in the
961  // full Jacobian (i.e. the matrix of the linear system we're
962  // actually trying to solve); we can do with this copy whatever
963  // we want...
965  this->get_block(i,i,block);
966 
967  // Set up preconditioner (i.e. lu-decompose the block)
968  Block_preconditioner_pt[i]->setup(&block);
969 
970  // Done with this block now, so the diagonal block that we extracted
971  // above can go out of scope. Its LU decomposition (which is the only
972  // thing we need to apply the preconditioner in the
973  // preconditioner_solve(...) function) is retained in the associated
974  // sub-preconditioner/(in)exact solver(SuperLU).
975 
976  } // end of brace to make block go out of scope
977 
978  // Next set up the off diagonal mat vec operators
979  for(unsigned j=i+1;j<nblock_types;j++)
980  {
981  // Get the off diagonal block
982  CRDoubleMatrix block_matrix = this->get_block(i,j);
983 
984  // Create a matrix vector product operator
985  Off_diagonal_matrix_vector_product_pt(i,j) = new MatrixVectorProduct;
986 
987  // Setup the matrix vector product for the currrent block matrix
988  // and specify the column in the "big matrix" as final argument.
989  // This is needed for things to work properly in parallel -- don't ask!
990  this->setup_matrix_vector_product(
991  Off_diagonal_matrix_vector_product_pt(i,j),&block_matrix,j);
992 
993  // Done with this block now, so the diagonal block that we extracted
994  // above can go out of scope. The MatrixVectorProduct operator retains
995  // its own copy of whatever data it needs.
996 
997  } // End for loop over j
998  } // End for loop over i
999  } // End setup(...)
1000 
1001 
1002  //=============================================================================
1007  //=============================================================================
1008  template<typename MATRIX> void UpperTriangular<MATRIX>::
1010  {
1011  // Get number of blocks
1012  unsigned n_block = this->nblock_types();
1013 
1014  // vector of vectors for each section of rhs vector
1015  Vector<DoubleVector> block_r;
1016 
1017  // rearrange the vector r into the vector of block vectors block_r
1018  this->get_block_vectors(r,block_r);
1019 
1020  // Vector of vectors for the solution block vectors
1021  Vector<DoubleVector> block_z(n_block);
1022 
1023  // Required to be an int due to an unsigned being unable to be compared to a
1024  // negative number (because it would roll over).
1025  for (int i=n_block-1;i>-1;i--)
1026  {
1027  // Back substitute
1028  for (unsigned j=i+1;j<n_block;j++)
1029  {
1030  DoubleVector temp;
1031  Off_diagonal_matrix_vector_product_pt(i,j)->multiply(block_z[j],temp);
1032  block_r[i] -= temp;
1033  } // End for over j
1034 
1035  // Solve on the block
1036  this->Block_preconditioner_pt[i]->
1037  preconditioner_solve(block_r[i], block_z[i]);
1038  } // End for over i
1039 
1040  // Copy solution in block vectors block_r back to z
1041  this->return_block_vectors(block_z,z);
1042  }
1043 
1044  //========================start_of_clean_up_for_upper_triangular_class========
1046  //============================================================================
1047  template<typename MATRIX>
1049  {
1050  // Delete anything in Off_diagonal_matrix_vector_products
1051  for(unsigned i=0,ni=Off_diagonal_matrix_vector_product_pt.nrow();i<ni;i++)
1052  {
1053  for(unsigned j=0,nj=Off_diagonal_matrix_vector_product_pt.ncol();j<nj;j++)
1054  {
1055  if(Off_diagonal_matrix_vector_product_pt(i,j) != 0)
1056  {
1057  delete Off_diagonal_matrix_vector_product_pt(i,j);
1058  Off_diagonal_matrix_vector_product_pt(i,j) = 0;
1059  }
1060  }
1061  }
1062 
1063  // Delete preconditioners (approximate solvers)
1064  unsigned n_block = Block_preconditioner_pt.size();
1065  for (unsigned i=0;i<n_block;i++)
1066  {
1067  if(Block_preconditioner_pt[i]!=0)
1068  {
1069  delete Block_preconditioner_pt[i];
1070  Block_preconditioner_pt[i]=0;
1071  }
1072  }
1073  } // End of clean_up_my_memory function.
1074 
1078 
1079 //=======================start_of_two_plus_three_class=========================
1083 //=============================================================================
1084  template<typename MATRIX>
1085  class TwoPlusThree : public BlockPreconditioner<MATRIX>
1086  {
1087  public :
1088 
1093  {
1095  } // end_of_constructor
1096 
1099  {
1100  this->clean_up_my_memory();
1101  }
1103  virtual void clean_up_my_memory();
1104 
1107  (const TwoPlusThree&)
1108  {
1109  BrokenCopy::broken_copy("TwoPlusThree");
1110  }
1111 
1113  void operator=(const TwoPlusThree&)
1114  {
1115  BrokenCopy::broken_assign("TwoPlusThree");
1116  }
1117 
1120 
1122  virtual void setup();
1123 
1125  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
1126  {
1127  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
1128  }
1129 
1130  private :
1131 
1135 
1139 
1143  };
1144 
1145  //====================start_of_setup_for_two_plus_three=======================
1147  //============================================================================
1148  template<typename MATRIX>
1150  {
1151  // Clean up memory.
1152  this->clean_up_my_memory();
1153 
1154 #ifdef PARANOID
1155  if (Multi_poisson_mesh_pt == 0)
1156  {
1157  std::stringstream err;
1158  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
1159  throw OomphLibError(err.str(),
1162  }
1163 #endif
1164 
1165  // The preconditioner works with one mesh; set it!
1166  this->set_nmesh(1);
1167  this->set_mesh(0,Multi_poisson_mesh_pt);
1168 
1169  // How many dof types do we have?
1170  unsigned n_dof_types = this->ndof_types();
1171 
1172 
1173 #ifdef PARANOID
1174  // This preconditioner only works for 5 dof types
1175  if (n_dof_types!=5)
1176  {
1177  std::stringstream tmp;
1178  tmp << "This preconditioner only works for problems with 5 dof types\n"
1179  << "Yours has " << n_dof_types;
1180  throw OomphLibError(tmp.str(),
1183  }
1184 #endif
1185 
1186 
1187  // Combine into two blocks, one containing dof types 0 and 1, the
1188  // final one dof types 2-4. In general we want:
1189  // dof_to_block_map[dof_type] = block type
1190  Vector<unsigned> dof_to_block_map(n_dof_types);
1191  dof_to_block_map[0]=0;
1192  dof_to_block_map[1]=0;
1193  dof_to_block_map[2]=1;
1194  dof_to_block_map[3]=1;
1195  dof_to_block_map[4]=1;
1196  this->block_setup(dof_to_block_map);
1197 
1198  // Show that it worked ok:
1199  oomph_info << "Preconditioner has "
1200  << this->nblock_types() << " block types\n";
1201 
1202  // Create the subsidiary preconditioners
1203  First_subsidiary_preconditioner_pt= new SuperLUPreconditioner;
1204  Second_subsidiary_preconditioner_pt= new SuperLUPreconditioner;
1205 
1206  // Set diagonal solvers/preconditioners; put in own scope
1207  // so variable block goes out of scope
1208  {
1210  this->get_block(0,0,block);
1211 
1212  // Set up preconditioner (i.e. lu-decompose the block)
1213  First_subsidiary_preconditioner_pt->setup(&block);
1214  }
1215  {
1217  this->get_block(1,1,block);
1218 
1219  // Set up preconditioner (i.e. lu-decompose the block)
1220  Second_subsidiary_preconditioner_pt->setup(&block);
1221  }
1222 
1223  } // End of setup
1224 
1225 
1226  //=============================================================================
1231  //=============================================================================
1232  template<typename MATRIX>
1235  {
1236  // Get number of blocks
1237  unsigned n_block = this->nblock_types();
1238 
1239  // Split up rhs vector into sub-vectors, arranged to match the matrix blocks.
1240  Vector<DoubleVector> block_r;
1241  this->get_block_vectors(r,block_r);
1242 
1243  // Create storage for solution of block solves
1244  Vector<DoubleVector> block_z(n_block);
1245 
1246  // Solve (0,0) diagonal block system
1247  First_subsidiary_preconditioner_pt->preconditioner_solve(block_r[0],
1248  block_z[0]);
1249 
1250  // Solve (1,1) diagonal block system
1251  Second_subsidiary_preconditioner_pt->preconditioner_solve(block_r[1],
1252  block_z[1]);
1253 
1254  // Copy solution in block vectors block_z back to z
1255  this->return_block_vectors(block_z,z);
1256  }
1257 
1258 
1259  //====================start_of_clean_up_for_two_plus_three====================
1261  //============================================================================
1262  template<typename MATRIX>
1264  {
1265  //Clean up subsidiary preconditioners.
1266  if(First_subsidiary_preconditioner_pt!=0)
1267  {
1268  delete First_subsidiary_preconditioner_pt;
1269  First_subsidiary_preconditioner_pt = 0;
1270  }
1271  if(Second_subsidiary_preconditioner_pt!=0)
1272  {
1273  delete Second_subsidiary_preconditioner_pt;
1274  Second_subsidiary_preconditioner_pt = 0;
1275  }
1276  } // End of clean_up_my_memory function.
1277 
1281 
1282 
1283 //=================start_of_two_plus_three_upper_triangular_class==============
1286 //=============================================================================
1287  template<typename MATRIX>
1289  : public BlockPreconditioner<MATRIX>
1290  {
1291 
1292  public :
1293 
1296  BlockPreconditioner<MATRIX>(),
1300  {
1302  }
1303 
1306  {
1307  this->clean_up_my_memory();
1308  }
1309 
1311  virtual void clean_up_my_memory();
1312 
1315  {
1316  BrokenCopy::broken_copy("TwoPlusThreeUpperTriangular");
1317  }
1318 
1321  {
1322  BrokenCopy::broken_assign("TwoPlusThreeUpperTriangular");
1323  }
1324 
1327 
1329  void setup();
1330 
1331  // Use the version in the Preconditioner base class for the alternative
1332  // setup function that takes a matrix pointer as an argument.
1333  using Preconditioner::setup;
1334 
1336  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
1337  {
1338  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
1339  }
1340 
1341  private:
1342 
1345 
1349 
1353 
1357 
1358  };
1359 
1360  //==============start_of_setup_for_two_plus_three_upper_triangular_class=======
1362  //============================================================================
1363  template<typename MATRIX>
1365  {
1366  // clean the memory
1367  this->clean_up_my_memory();
1368 
1369 #ifdef PARANOID
1370  if (Multi_poisson_mesh_pt == 0)
1371  {
1372  std::stringstream err;
1373  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
1374  throw OomphLibError(err.str(),
1377  }
1378 #endif
1379 
1380  // The preconditioner works with one mesh; set it!
1381  this->set_nmesh(1);
1382  this->set_mesh(0,Multi_poisson_mesh_pt);
1383 
1384  // Get number of degrees of freedom.
1385  unsigned n_dof_types = this->ndof_types();
1386 
1387 #ifdef PARANOID
1388  // This preconditioner only works for 5 dof types
1389  if (n_dof_types!=5)
1390  {
1391  std::stringstream tmp;
1392  tmp << "This preconditioner only works for problems with 5 dof types\n"
1393  << "Yours has " << n_dof_types;
1394  throw OomphLibError(tmp.str(),
1397  }
1398 #endif
1399 
1400  // Combine into two major blocks, one containing dof types 0 and 1, the
1401  // final one dof types 2-4. In general we want
1402  // dof_to_block_map[dof_type] = block_type
1403  Vector<unsigned> dof_to_block_map(n_dof_types);
1404  dof_to_block_map[0]=0;
1405  dof_to_block_map[1]=0;
1406  dof_to_block_map[2]=1;
1407  dof_to_block_map[3]=1;
1408  dof_to_block_map[4]=1;
1409  this->block_setup(dof_to_block_map);
1410 
1411  // Create the subsidiary preconditioners
1412  First_subsidiary_preconditioner_pt= new SuperLUPreconditioner;
1413  Second_subsidiary_preconditioner_pt= new SuperLUPreconditioner;
1414 
1415  // Set diagonal solvers/preconditioners; put in own scope
1416  // so block goes out of scope
1417  {
1418 
1420  this->get_block(0,0,block);
1421 
1422  // Set up preconditioner (i.e. lu-decompose the block)
1423  First_subsidiary_preconditioner_pt->setup(&block);
1424 
1425  }
1426  {
1427 
1429  this->get_block(1,1,block);
1430 
1431  // Set up preconditioner (i.e. lu-decompose the block)
1432  Second_subsidiary_preconditioner_pt->setup(&block);
1433 
1434  } // end setup of last subsidiary preconditioner
1435 
1436 
1437  // next setup the off diagonal mat vec operators
1438  {
1439  // Get the block
1440  CRDoubleMatrix block_matrix = this->get_block(0,1);
1441 
1442  // Create matrix vector product
1443  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
1444 
1445  // Set it up -- note that the block column index refers to the
1446  // block enumeration (not the dof enumeration)
1447  unsigned block_column_index=1;
1448  this->setup_matrix_vector_product(
1449  Off_diagonal_matrix_vector_product_pt,&block_matrix,block_column_index);
1450  }
1451 
1452  }
1453 
1454  //=============================================================================
1460  //=============================================================================
1461  template<typename MATRIX>
1464  {
1465  // Get number of blocks
1466  unsigned n_block = this->nblock_types();
1467 
1468  // Split up rhs vector into sub-vectors, rarranged to match the matrix blocks.
1469  Vector<DoubleVector> block_r;
1470  this->get_block_vectors(r,block_r);
1471 
1472  // Create storage for solution of block solves
1473  Vector<DoubleVector> block_z(n_block);
1474 
1475  // Solve (1,1) diagonal block system
1476  Second_subsidiary_preconditioner_pt->preconditioner_solve(block_r[1],
1477  block_z[1]);
1478 
1479  // Solve (0,1) off diagonal.
1480  // Substitute
1481  DoubleVector temp;
1482  Off_diagonal_matrix_vector_product_pt->multiply(block_z[1],temp);
1483  block_r[0] -= temp;
1484 
1485  // Solve (0,0) diagonal block system
1486  First_subsidiary_preconditioner_pt->preconditioner_solve(block_r[0],
1487  block_z[0]);
1488 
1489  // Copy solution in block vectors block_z back to z
1490  this->return_block_vectors(block_z,z);
1491  }
1492 
1493 
1494  //===========start_of_clean_up_for_two_plus_three_upper_triangular_class======
1496  //============================================================================
1497  template<typename MATRIX>
1499  {
1500  // Delete of diagonal matrix vector product
1501  if (Off_diagonal_matrix_vector_product_pt != 0)
1502  {
1503  delete Off_diagonal_matrix_vector_product_pt;
1504  Off_diagonal_matrix_vector_product_pt = 0;
1505  }
1506 
1507  //Clean up subsidiary preconditioners.
1508  if(First_subsidiary_preconditioner_pt!=0)
1509  {
1510  delete First_subsidiary_preconditioner_pt;
1511  First_subsidiary_preconditioner_pt = 0;
1512  }
1513  if(Second_subsidiary_preconditioner_pt!=0)
1514  {
1515  delete Second_subsidiary_preconditioner_pt;
1516  Second_subsidiary_preconditioner_pt = 0;
1517  }
1518  } // End of clean_up_my_memory function.
1519 
1520 
1521 
1525 
1526 
1527 //=========start_of_two_plus_three_upper_triangular_with_sub_class=============
1530 //=============================================================================
1531  template<typename MATRIX>
1533  : public BlockPreconditioner<MATRIX>
1534  {
1535 
1536  public :
1537 
1540  BlockPreconditioner<MATRIX>(),
1544  {
1546  }
1547 
1550  {
1551  this->clean_up_my_memory();
1552  }
1553 
1555  void clean_up_my_memory();
1556 
1560  {
1562  ("TwoPlusThreeUpperTriangularWithOneLevelSubsidiary");
1563  }
1564 
1566  void operator=(const
1568  {
1570  "TwoPlusThreeUpperTriangularWithOneLevelSubsidiary");
1571  }
1572 
1575 
1577  void setup();
1578 
1579  // Use the version in the Preconditioner base class for the alternative
1580  // setup function that takes a matrix pointer as an argument.
1581  using Preconditioner::setup;
1582 
1584  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
1585  {
1586  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
1587  }
1588 
1589  private:
1590 
1593 
1597 
1601 
1605 
1606  };
1607 
1608  //=======start_of_setup_for_two_plus_three_upper_triangular_with_sub_class====
1610  //============================================================================
1611  template<typename MATRIX>
1613  {
1614  // clean the memory
1615  this->clean_up_my_memory();
1616 
1617 #ifdef PARANOID
1618  if (Multi_poisson_mesh_pt == 0)
1619  {
1620  std::stringstream err;
1621  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
1622  throw OomphLibError(err.str(),
1625  }
1626 #endif
1627 
1628  // The preconditioner works with one mesh; set it!
1629  this->set_nmesh(1);
1630  this->set_mesh(0,Multi_poisson_mesh_pt);
1631 
1632  // number of dof types
1633  unsigned n_dof_types = this->ndof_types();
1634 
1635 #ifdef PARANOID
1636  // This preconditioner only works for 5 dof types
1637  if (n_dof_types!=5)
1638  {
1639  std::stringstream tmp;
1640  tmp << "This preconditioner only works for problems with 5 dof types\n"
1641  << "Yours has " << n_dof_types;
1642  throw OomphLibError(tmp.str(),
1645  }
1646 #endif
1647 
1648  // Combine "dof blocks" into two compound blocks, one containing dof
1649  // types 0 and 1, the final one dof types 2-4. In general we want:
1650  // dof_to_block_map[dof_type] = block type
1651  Vector<unsigned> dof_to_block_map(n_dof_types);
1652  dof_to_block_map[0]=0;
1653  dof_to_block_map[1]=0;
1654  dof_to_block_map[2]=1;
1655  dof_to_block_map[3]=1;
1656  dof_to_block_map[4]=1;
1657  this->block_setup(dof_to_block_map);
1658 
1659  // Create the subsidiary block preconditioners.
1660  {
1661  // Block upper triangular block preconditioner for compound
1662  // 2x2 top left block in "big" 5x5 matrix
1663  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
1665  First_subsidiary_preconditioner_pt=block_prec_pt;
1666 
1667  // Set mesh
1668  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
1669 
1670  // Turn into a subsidiary preconditioner, declaring which
1671  // of the five dof types in the present (master) preconditioner
1672  // correspond to the dof types in the subsidiary block preconditioner:
1673  // dof_map[dof_block_ID_in_subsdiary] = dof_block_ID_in_master. Also
1674  // pass pointer to present (master) preconditioner.
1675  unsigned n_sub_dof_types=2;
1676  Vector<unsigned> dof_map(n_sub_dof_types);
1677  dof_map[0]=0;
1678  dof_map[1]=1;
1679  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
1680 
1681  // Setup: Pass pointer to full-size matrix!
1682  block_prec_pt->setup(this->matrix_pt());
1683  }
1684 
1685  {
1686  // Block upper triangular for 3x3 bottom right block in "big" 5x5 matrix
1687  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
1689  Second_subsidiary_preconditioner_pt=block_prec_pt;
1690 
1691  // Set mesh
1692  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
1693 
1694  // Turn second_sub into a subsidiary preconditioner, declaring which
1695  // of the five dof types in the present (master) preconditioner
1696  // correspond to the dof types in the subsidiary block preconditioner:
1697  // dof_map[dof_block_ID_in_subsdiary] = dof_block_ID_in_master. Also
1698  // pass pointer to present (master) preconditioner.
1699  unsigned n_sub_dof_types=3;
1700  Vector<unsigned> dof_map(n_sub_dof_types);
1701  dof_map[0]=2;
1702  dof_map[1]=3;
1703  dof_map[2]=4;
1704  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
1705 
1706  // Setup: Pass pointer to full-size matrix!
1707  block_prec_pt->setup(this->matrix_pt());
1708  }
1709 
1710  // Setup the off-diagonal mat vec operator
1711  {
1712  // Get the off-diagonal block: the top-right block in the present
1713  // block preconditioner (which views the system matrix as comprising
1714  // 2x2 blocks).
1715  CRDoubleMatrix block_matrix = this->get_block(0,1);
1716 
1717  // Create matrix vector product
1718  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
1719 
1720  // Setup: Final argument indicates block column in the present
1721  // block preconditioner (which views the system matrix as comprising
1722  // 2x2 blocks).
1723  unsigned block_column_index=1;
1724  this->setup_matrix_vector_product(
1725  Off_diagonal_matrix_vector_product_pt,&block_matrix,block_column_index);
1726  }
1727 
1728  }
1729 
1730  //=============================================================================
1732  //=============================================================================
1733  template<typename MATRIX>
1736  {
1737  // Solve "bottom right" (1,1) diagonal block system, using the
1738  // subsidiary block preconditioner that acts on the
1739  // "bottom right" 3x3 sub-system (only!). The subsidiary preconditioner
1740  // will extract the relevant (3x1) "sub-vectors" from the "big" (5x1)
1741  // vector z and treat it as the rhs, r, of P y = z
1742  // where P is 3x3 a block matrix. Once the system is solved,
1743  // the result is automatically put back into the appropriate places
1744  // of the "big" (5x1) vector y:
1745  Second_subsidiary_preconditioner_pt->preconditioner_solve(z,y);
1746 
1747  // Now extract the "bottom" (3x1) block vector from the full-size (5x1)
1748  // solution vector that we've just computed -- note that index 1
1749  // refers to the block enumeration in the current preconditioner
1750  // (which has two blocks!)
1751  DoubleVector block_y;
1752  this->get_block_vector(1,y,block_y);
1753 
1754  // Evaluate matrix vector product of just-extracted (3x1) solution
1755  // vector with off-diagonal block and store in temporary vector
1756  DoubleVector temp;
1757  Off_diagonal_matrix_vector_product_pt->multiply(block_y,temp);
1758 
1759  // Extract "upper" (2x1) block vector from full-size (5x1) rhs
1760  // vector (as passed into this function)...
1761  DoubleVector block_z;
1762  this->get_block_vector(0,z,block_z);
1763 
1764  // ...and subtract matrix vector product computed above
1765  block_z -= temp;
1766 
1767  // Block solve for first diagonal block. Since the associated subsidiary
1768  // preconditioner is a block preconditioner itself, it will extract
1769  // the required (2x1) block from a "big" (5x1) rhs vector.
1770  // Therefore we first put the actual (2x1) rhs vector block_z into a
1771  // "big" (5x1) vector big_z whose row distribution matches that of the
1772  // "big" right hand side vector, z, that was passed into this function.
1773  DoubleVector big_z(z.distribution_pt());
1774  this->return_block_vector(0,block_z,big_z);
1775 
1776  // Now apply the subsidiary block preconditioner that acts on the
1777  // "upper left" (2x2) sub-system (only!). The subsidiary preconditioner
1778  // will extract the relevant (2x1) block vector from the "big" (5x1)
1779  // vector big_r and treat it as the rhs, z, of its P y = z
1780  // where P is upper left 2x2 block diagonal of the big system.
1781  // Once the system is solved, the result is automatically put back
1782  // into the appropriate places of the "big" (5x1) vector y which is
1783  // returned by the current function, so no further action is required.
1784  First_subsidiary_preconditioner_pt->preconditioner_solve(big_z,y);
1785  }
1786 
1787  //====start_of_clean_up_for_two_plus_three_upper_triangular_with_sub_class=====
1789  //============================================================================
1790  template<typename MATRIX>
1793  {
1794  // Delete off-diagonal matrix vector product
1795  if(Off_diagonal_matrix_vector_product_pt!= 0)
1796  {
1797  delete Off_diagonal_matrix_vector_product_pt;
1798  Off_diagonal_matrix_vector_product_pt = 0;
1799  }
1800 
1801  //Clean up subsidiary preconditioners.
1802  if(First_subsidiary_preconditioner_pt!=0)
1803  {
1804  delete First_subsidiary_preconditioner_pt;
1805  First_subsidiary_preconditioner_pt = 0;
1806  }
1807  if(Second_subsidiary_preconditioner_pt!=0)
1808  {
1809  delete Second_subsidiary_preconditioner_pt;
1810  Second_subsidiary_preconditioner_pt = 0;
1811  }
1812  } // End of clean_up_my_memory function.
1813 
1817 
1818 //====================start_of_two_plus_one_class=============================
1825 //=============================================================================
1826 template<typename MATRIX>
1828 public BlockPreconditioner<MATRIX>
1829  {
1830 
1831  public :
1832 
1835  BlockPreconditioner<MATRIX>(),
1839  {
1841  } // end_of_constructor
1842 
1843 
1846  {
1847  this->clean_up_my_memory();
1848  }
1849 
1850 
1852  virtual void clean_up_my_memory();
1853 
1857  {
1858  BrokenCopy::broken_copy("TwoPlusOneUpperTriangularPreconditioner");
1859  }
1860 
1863  {
1864  BrokenCopy::broken_assign("TwoPlusOneUpperTriangularPreconditioner");
1865  }
1866 
1869 
1871  void setup();
1872 
1873  // Use the version in the Preconditioner base class for the alternative
1874  // setup function that takes a matrix pointer as an argument.
1875  using Preconditioner::setup;
1876 
1878  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
1879  {
1880  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
1881  }
1882 
1883  private :
1884 
1888 
1892 
1895 
1899 
1900  };
1901 
1902 //================start_of_setup_for_two_plus_one_preconditioner=============
1904 //===========================================================================
1905 template<typename MATRIX>
1907  {
1908  // Clean up memory.
1909  this->clean_up_my_memory();
1910 
1911 #ifdef PARANOID
1912  if (Multi_poisson_mesh_pt == 0)
1913  {
1914  std::stringstream err;
1915  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
1916  throw OomphLibError(err.str(),
1919  }
1920 #endif
1921 
1922  // The preconditioner works with one mesh; set it!
1923  this->set_nmesh(1);
1924  this->set_mesh(0,Multi_poisson_mesh_pt);
1925 
1926 
1927 #ifdef PARANOID
1928  // This preconditioner only works for 3 dof types
1929  unsigned n_dof_types = this->ndof_types();
1930  if (n_dof_types!=3)
1931  {
1932  std::stringstream tmp;
1933  tmp << "This preconditioner only works for problems with 3 dof types\n"
1934  << "Yours has " << n_dof_types;
1935  throw OomphLibError(tmp.str(),
1938  }
1939 #endif
1940 
1941  // Combine into two major blocks, one containing dofs 0 and 1, the
1942  // final one dof, 2.
1943 
1944  Vector<unsigned> dof_to_block_map(3);
1945  dof_to_block_map[0]=0;
1946  dof_to_block_map[1]=0;
1947  dof_to_block_map[2]=1;
1948  this->block_setup(dof_to_block_map);
1949 
1950  // Create the subsidiary preconditioners
1951  //--------------------------------------
1952 
1953  // First one:
1954  {
1955  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
1957  First_subsidiary_preconditioner_pt=block_prec_pt;
1958 
1959  // Set mesh
1960  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
1961 
1962  // Turn it into a subsidiary preconditioner, declaring which
1963  // of the three dof types in the present (master) preconditioner
1964  // correspond to the dof types in the subsidiary block preconditioner,
1965  // i.e. arguments: dof_map[doc_in_subsidiary]=dof_in_present
1966  unsigned n_sub_dof_types=2;
1967  Vector<unsigned> dof_map(n_sub_dof_types);
1968  dof_map[0] = 0;
1969  dof_map[1] = 1;
1970  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
1971 
1972  // Perform setup. Note that because the subsidiary
1973  // preconditioner is a block preconditioner itself it is given
1974  // the pointer to the "full" matrix
1975  block_prec_pt->setup(this->matrix_pt());
1976  }
1977 
1978 
1979  // Second one:
1980  {
1981  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
1983  Second_subsidiary_preconditioner_pt=block_prec_pt;
1984 
1985  // Set mesh
1986  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
1987 
1988  // Turn it into a subsidiary preconditioner, declaring which
1989  // of the three dof types in the present (master) preconditioner
1990  // correspond to the dof types in the subsidiary block preconditioner i.e.
1991  // arguments: dof_map[doc_in_subsidiary]=dof_in_present
1992  unsigned n_sub_dof_types=1;
1993  Vector<unsigned> dof_map(n_sub_dof_types);
1994  dof_map[0] = 2;
1995  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
1996 
1997  // Perform setup. Note that because the subsidiary
1998  // preconditioner is a block preconditioner itself it is given
1999  // the pointer to the "full" matrix
2000  block_prec_pt->setup(this->matrix_pt());
2001  }
2002 
2003 
2004  // Set up off diagonal matrix vector product operator.
2005  {
2006  // Get the block
2007  CRDoubleMatrix block_matrix = this->get_block(0,1);
2008 
2009  // Create matrix vector product operator
2010  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
2011 
2012  // Setup: Final argument indicates block column in the present
2013  // block preconditioner (which views the system matrix as comprising
2014  // 2x2 blocks).
2015  unsigned block_column_index=1;
2016  this->setup_matrix_vector_product(
2017  Off_diagonal_matrix_vector_product_pt,&block_matrix,block_column_index);
2018 
2019  // Extracted block can now go out of scope since the
2020  // matrix vector product operators stores what it needs
2021  }
2022 
2023  }
2024 
2025 
2026  //=============================================================================
2029  //=============================================================================
2030  template<typename MATRIX>
2033  {
2034  // Solve (1,1) diagonal block system:
2035  // Apply the subsidiary block preconditioner that acts on the
2036  // "bottom right" 1x1 sub-system (only!). The subsidiary preconditioner
2037  // will extract the relevant (1x1) "sub-vectors" from the "big" (3x1)
2038  // vector big_r and treat it as the rhs, r, of P z = r
2039  // where P is 1x1 block diagonal. Once the system is solved,
2040  // the result is automatically put back into the appropriate places
2041  // of the "big" (3x1) vector z:
2042  Second_subsidiary_preconditioner_pt->preconditioner_solve(r,z);
2043 
2044  // Perform matrix vector product with (0,1) off diagonal.
2045  DoubleVector temp;
2046  DoubleVector z_1;
2047  this->get_block_vector(1,z,z_1);
2048  Off_diagonal_matrix_vector_product_pt->multiply(z_1,temp);
2049 
2050  // Get r_0 from the RHS and modify it accordingly.
2051  DoubleVector r_0;
2052  this->get_block_vector(0,r,r_0);
2053  r_0 -= temp;
2054 
2055 
2056  // Block solve for first diagonal block. Since the associated subsidiary
2057  // preconditioner is a block preconditioner itself, it will extract
2058  // the required (2x1) block rhs from a "big" (3x1) rhs vector, big_r.
2059  // Therefore we first put the actual (2x1) rhs vector r_0 into the
2060  // "big" (3x1) vector big_r.
2061  DoubleVector big_r(z.distribution_pt());
2062  this->return_block_vector(0,r_0,big_r);
2063 
2064  // Now apply the subsidiary block preconditioner that acts on the
2065  // "top left" 2x2 sub-system (only!). The subsidiary preconditioner
2066  // will extract the relevant (2x1) "sub-vectors" from the "big" (3x1)
2067  // vector big_r and treat it as the rhs, r, of P z = r
2068  // where P is 2x2 block diagonal. Once the system is solved,
2069  // the result is automatically put back into the appropriate places
2070  // of the "big" (3x1) vector z:
2071  First_subsidiary_preconditioner_pt->preconditioner_solve(big_r,z);
2072  }
2073 
2074  //================start_of_clean_up_for_two_plus_one_preconditioner==========
2076  //===========================================================================
2077  template<typename MATRIX>
2079  {
2080  // Delete diagonal preconditioners (approximate solvers)
2081  if(First_subsidiary_preconditioner_pt!=0)
2082  {
2083  delete First_subsidiary_preconditioner_pt;
2084  First_subsidiary_preconditioner_pt = 0;
2085  }
2086  if(Second_subsidiary_preconditioner_pt!=0)
2087  {
2088  delete Second_subsidiary_preconditioner_pt;
2089  Second_subsidiary_preconditioner_pt = 0;
2090  }
2091  if(Off_diagonal_matrix_vector_product_pt!=0)
2092  {
2093  delete Off_diagonal_matrix_vector_product_pt;
2094  Off_diagonal_matrix_vector_product_pt = 0;
2095  }
2096  } // End of clean_up_my_memory function.
2097 
2101 
2102 
2103 //=========start_of_two_plus_three_upper_triangular_with_two_sub_class=========
2106 //=============================================================================
2107  template<typename MATRIX>
2109  : public BlockPreconditioner<MATRIX>
2110  {
2111 
2112  public :
2113 
2116  BlockPreconditioner<MATRIX>(),
2120  {
2122  }
2123 
2126  {
2127  this->clean_up_my_memory();
2128  }
2129 
2131  virtual void clean_up_my_memory();
2132 
2136  {
2138  "TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary");
2139  }
2140 
2142  void operator=(const
2144  {
2146  "TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary");
2147  }
2148 
2151 
2153  void setup();
2154 
2155  // Use the version in the Preconditioner base class for the alternative
2156  // setup function that takes a matrix pointer as an argument.
2157  using Preconditioner::setup;
2158 
2160  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
2161  {
2162  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
2163  }
2164 
2165  private:
2166 
2169 
2173 
2177 
2181 
2182  };
2183 
2184  //===start_of_setup_for_two_plus_three_upper_triangular_with_two_sub_class=====
2186  //============================================================================
2187  template<typename MATRIX>
2189  {
2190  // clean the memory
2191  this->clean_up_my_memory();
2192 
2193 #ifdef PARANOID
2194  if (Multi_poisson_mesh_pt == 0)
2195  {
2196  std::stringstream err;
2197  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
2198  throw OomphLibError(err.str(),
2201  }
2202 #endif
2203 
2204  // The preconditioner works with one mesh; set it!
2205  this->set_nmesh(1);
2206  this->set_mesh(0,Multi_poisson_mesh_pt);
2207 
2208  // number of block types
2209  unsigned n_dof_types = this->ndof_types();
2210 
2211 #ifdef PARANOID
2212  // This preconditioner only works for 5 dof types
2213  if (n_dof_types!=5)
2214  {
2215  std::stringstream tmp;
2216  tmp << "This preconditioner only works for problems with 5 dof types\n"
2217  << "Yours has " << n_dof_types;
2218  throw OomphLibError(tmp.str(),
2221  }
2222 #endif
2223 
2224 
2225  // Combine into two major blocks, one containing dof types 0 and 1, the
2226  // final one dof types 2-4. In general we want
2227  // dof_to_block_map[dof_type] = block type
2228  Vector<unsigned> dof_to_block_map(n_dof_types);
2229  dof_to_block_map[0]=0;
2230  dof_to_block_map[1]=0;
2231  dof_to_block_map[2]=1;
2232  dof_to_block_map[3]=1;
2233  dof_to_block_map[4]=1;
2234  this->block_setup(dof_to_block_map);
2235 
2236  // Show that it worked ok:
2237  oomph_info << "Preconditioner has " << this->nblock_types()
2238  << " block types\n";
2239 
2240  // Create the subsidiary preconditioners.
2241 
2242  // First subsidiary precond is a block diagonal preconditioner itself.
2243  {
2244  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
2246  First_subsidiary_preconditioner_pt=block_prec_pt;
2247 
2248  // Set mesh
2249  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
2250 
2251  // Turn first_sub into a subsidiary preconditioner, declaring which
2252  // of the five dof types in the present (master) preconditioner
2253  // correspond to the dof types in the subsidiary block preconditioner,
2254  // i.e. arguments: dof_map[doc_in_subsidiary]=dof_in_present
2255  unsigned n_sub_dof_types=2;
2256  Vector<unsigned> dof_map(n_sub_dof_types);
2257  dof_map[0]=0;
2258  dof_map[1]=1;
2259  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
2260 
2261  // Perform setup.Note that because the subsidiary
2262  // preconditioner is a block preconditioner itself it is given
2263  // the pointer to the "full" matrix
2264  block_prec_pt->setup(this->matrix_pt());
2265  }
2266 
2267  // Second subsidiary precond is a block diagonal preconditioner itself
2268  {
2271  Second_subsidiary_preconditioner_pt=block_prec_pt;
2272 
2273  // Set mesh
2274  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
2275 
2276  // Turn second_sub into a subsidiary preconditioner, declaring which
2277  // of the five dof types in the present (master) preconditioner
2278  // correspond to the dof types in the subsidiary block preconditioner,
2279  // i.e. arguments: dof_map[doc_in_subsidiary]=dof_in_present
2280  unsigned n_sub_dof_types=3;
2281  Vector<unsigned> dof_map(n_sub_dof_types);
2282  dof_map[0]=2;
2283  dof_map[1]=3;
2284  dof_map[2]=4;
2285  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
2286 
2287  // Perform setup. Note that because the subsidiary
2288  // preconditioner is a block preconditioner itself it is given
2289  // the pointer to the "full" matrix
2290  block_prec_pt->setup(this->matrix_pt());
2291  }
2292 
2293  // Set up the off diagonal mat vec operators
2294  {
2295  // Get the block
2296  CRDoubleMatrix block_matrix = this->get_block(0,1);
2297 
2298  // Create matrix vector product operator
2299  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
2300 
2301  // Setup: Final argument indicates block column in the present
2302  // block preconditioner (which views the system matrix as comprising
2303  // 2x2 blocks).
2304  unsigned block_column_index=1;
2305  this->setup_matrix_vector_product(
2306  Off_diagonal_matrix_vector_product_pt,&block_matrix,block_column_index);
2307 
2308  // Block can now go out of scope since the matrix vector product operator
2309  // stores what it needs
2310  }
2311 
2312  }
2313 
2314  //=============================================================================
2320  //=============================================================================
2321  template<typename MATRIX>
2324  {
2325  // Solve (1,1) diagonal block system
2326  // Apply the subsidiary block preconditioner that acts on the
2327  // "bottom right" 3x3 sub-system (only!). The subsidiary preconditioner
2328  // will extract the relevant (3x1) "sub-vectors" from the "big" (5x1)
2329  // vector big_r and treat it as the rhs, r, of P z = r
2330  // where P is 3x3 block diagonal. Once the system is solved,
2331  // the result is automatically put back into the appropriate places
2332  // of the "big" (5x1) vector z:
2333  Second_subsidiary_preconditioner_pt->preconditioner_solve(r,z);
2334 
2335  // Get number of blocks
2336  unsigned n_block = this->nblock_types();
2337 
2338  // Split up rhs vector into sub-vectors, re-arranged to match
2339  // the matrix blocks
2340  Vector<DoubleVector> block_r;
2341  this->get_block_vectors(r,block_r);
2342 
2343  // Create storage for solution of block solves
2344  Vector<DoubleVector> block_z(n_block);
2345 
2346  // Multiply by (0,1) off diagonal.
2347  this->get_block_vectors(z,block_z);
2348  DoubleVector temp;
2349  Off_diagonal_matrix_vector_product_pt->multiply(block_z[1],temp);
2350  block_r[0] -= temp;
2351 
2352  // Block solve for first diagonal block. Since the associated subsidiary
2353  // preconditioner is a block preconditioner itself, it will extract
2354  // the required (2x1) block rhs from a "big" (5x1) rhs vector, big_r.
2355  // Therefore we first put the actual (2x1) rhs vector block_r[0] into the
2356  // "big" (5x1) vector big_r.
2357  DoubleVector big_r(z.distribution_pt());
2358  this->return_block_vector(0,block_r[0],big_r);
2359 
2360  // Now apply the subsidiary block preconditioner that acts on the
2361  // "upper left" 2x2 sub-system (only!). The subsidiary preconditioner
2362  // will extract the relevant (2x1) "sub-vectors" from the "big" (5x1)
2363  // vector big_r and treat it as the rhs, r, of P z = r
2364  // where P is 2x2 block diagonal. Once the system is solved,
2365  // the result is automatically put back into the appropriate places
2366  // of the "big" (5x1) vector z:
2367  First_subsidiary_preconditioner_pt->preconditioner_solve(big_r,z);
2368  }
2369 
2370  //====start_of_clean_up_for_two_plus_three_upper_triangular_with_sub_class=====
2372  //============================================================================
2373  template<typename MATRIX>
2376  {
2377  // Clean up matrix vector product
2378  if(Off_diagonal_matrix_vector_product_pt!= 0)
2379  {
2380  delete Off_diagonal_matrix_vector_product_pt;
2381  Off_diagonal_matrix_vector_product_pt = 0;
2382  }
2383 
2384  //Clean up subsidiary preconditioners.
2385  if(First_subsidiary_preconditioner_pt!=0)
2386  {
2387  delete First_subsidiary_preconditioner_pt;
2388  First_subsidiary_preconditioner_pt = 0;
2389  }
2390  if(Second_subsidiary_preconditioner_pt!=0)
2391  {
2392  delete Second_subsidiary_preconditioner_pt;
2393  Second_subsidiary_preconditioner_pt = 0;
2394  }
2395  } // End of clean_up_my_memory function.
2396 
2397 
2398 
2402 
2403 
2404 //=============start_of_two_plus_three_upper_triangular_with_replace_class=====
2412 //=============================================================================
2413  template<typename MATRIX>
2415  public BlockPreconditioner<MATRIX>
2416  {
2417 
2418  public :
2419 
2422  BlockPreconditioner<MATRIX>(),
2426  {
2428  } // end_of_constructor
2429 
2430 
2433  {
2434  this->clean_up_my_memory();
2435  }
2436 
2438  virtual void clean_up_my_memory();
2439 
2443  {
2444  BrokenCopy::
2445  broken_copy("TwoPlusThreeUpperTriangularWithReplace");
2446  }
2447 
2450  {
2451  BrokenCopy::
2452  broken_assign("TwoPlusThreeUpperTriangularWithReplace");
2453  }
2454 
2457 
2459  void setup();
2460 
2462  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
2463  {
2464  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
2465  }
2466 
2467  private :
2468 
2472 
2476 
2480 
2481  // Matrix of pointers to replacement matrix blocks
2483 
2487 
2488  };
2489 
2490 
2491  //==start_of_setup_for_two_plus_three_upper_triangular_with_replace===========
2493  //============================================================================
2494  template<typename MATRIX>
2496  {
2497  // Clean up memory.
2498  this->clean_up_my_memory();
2499 
2500 #ifdef PARANOID
2501  if (Multi_poisson_mesh_pt == 0)
2502  {
2503  std::stringstream err;
2504  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
2505  throw OomphLibError(err.str(),
2508  }
2509 #endif
2510 
2511  // The preconditioner works with one mesh; set it!
2512  this->set_nmesh(1);
2513  this->set_mesh(0,Multi_poisson_mesh_pt);
2514 
2515  // How many dof types do we have?
2516  const unsigned n_dof_types = this->ndof_types();
2517 
2518 #ifdef PARANOID
2519  // This preconditioner only works for 5 dof types
2520  if (n_dof_types!=5)
2521  {
2522  std::stringstream tmp;
2523  tmp << "This preconditioner only works for problems with 5 dof types\n"
2524  << "Yours has " << n_dof_types;
2525  throw OomphLibError(tmp.str(),
2528  }
2529 #endif
2530 
2531  // Call block setup with the Vector [0,0,1,1,1] to:
2532  // Merge DOF types 0 and 1 into block type 0
2533  // Merge DOF types 2, 3, and 4 into block type 1.
2534  Vector<unsigned> dof_to_block_map(n_dof_types,0);
2535  dof_to_block_map[0] = 0;
2536  dof_to_block_map[1] = 0;
2537  dof_to_block_map[2] = 1;
2538  dof_to_block_map[3] = 1;
2539  dof_to_block_map[4] = 1;
2540  this->block_setup(dof_to_block_map);
2541 
2542 #ifdef PARANOID
2543 
2544  // We should now have two block types -- do we?
2545  const unsigned nblocks = this->nblock_types();
2546  if (nblocks!=2)
2547  {
2548  std::stringstream tmp;
2549  tmp << "Expected number of block types is 2.\n"
2550  << "Yours has " << nblocks << ".\n"
2551  << "Perhaps your argument to block_setup(...) is not correct.\n";
2552  throw OomphLibError(tmp.str(),
2555  }
2556 
2557 #endif
2558 
2559  // Now replace all the off-diagonal DOF blocks.
2560 
2561  // Storage for the replacement DOF blocks
2562  Replacement_matrix_pt.resize(n_dof_types,n_dof_types,0);
2563 
2564  // Set off-diagonal DOF blocks to zero, loop over the number of DOF blocks.
2565  // NOTE: There are two (compound) blocks, but the replacement functionality
2566  // works with DOF blocks.
2567  for(unsigned i=0;i<n_dof_types;i++)
2568  {
2569  for(unsigned j=0;j<n_dof_types;j++)
2570  {
2571  if(i!=j)
2572  {
2573  // Modify matrix
2574  bool modify_existing_matrix=true;
2575  if (modify_existing_matrix)
2576  {
2577  // Get the dof-block and make a deep copy of it
2578  Replacement_matrix_pt(i,j)=new CRDoubleMatrix;
2579  this->get_dof_level_block(i,j,(*Replacement_matrix_pt(i,j)));
2580 
2581  // Set all its entries to zero
2582  unsigned nnz=Replacement_matrix_pt(i,j)->nnz();
2583  for (unsigned k=0;k<nnz;k++)
2584  {
2585  Replacement_matrix_pt(i,j)->value()[k]=0.0;
2586  }
2587  } // done -- quite wasteful, we're actually storing lots of zeroes, but
2588  // this is just an example!
2589 
2590  // Build (zero) replacement matrix from scratch:
2591  else
2592  {
2593  // Get the DOF block's (row!) distribution.
2594  LinearAlgebraDistribution* dof_block_dist_pt=
2595  this->dof_block_distribution_pt(i);
2596 
2597  // Number of rows in DOF block matrix (i,j).
2598  const unsigned long dof_block_nrow_local
2599  = dof_block_dist_pt->nrow_local();
2600 
2601  // Number of columns in DOF block matrix (i,j) is the same as the
2602  // number of rows in block matrix (j,i).
2603  const unsigned long dof_block_ncol
2604  = this->dof_block_distribution_pt(j)->nrow();
2605 
2606  // Storage for replacement matrices:
2607  // Values
2608  Vector<double> replacement_value(0);
2609  // Column index
2610  Vector<int> replacement_column_index(0);
2611  // Row start
2612  Vector<int> replacement_row_start;
2613 
2614  // Need one row start per row, and one for the nnz, all of which are 0.
2615  // There are no rows, so this is a Vector of size 1.
2616  replacement_row_start.resize(dof_block_nrow_local+1,0);
2617 
2618  Replacement_matrix_pt(i,j)=
2619  new CRDoubleMatrix(dof_block_dist_pt,
2620  dof_block_ncol,
2621  replacement_value,
2622  replacement_column_index,
2623  replacement_row_start);
2624  }
2625 
2626  // Replace (i,j)-th dof block
2627  this->set_replacement_dof_block(i,j,Replacement_matrix_pt(i,j));
2628  }
2629  }// end for loop of j
2630  }// end for loop of i
2631 
2632 
2633  // First subsidiary precond is a block triangular preconditioner
2634  {
2635  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
2637  First_subsidiary_preconditioner_pt=block_prec_pt;
2638 
2639  // Set mesh
2640  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
2641 
2642  // Turn it into a subsidiary preconditioner, declaring which
2643  // of the five dof types in the present (master) preconditioner
2644  // correspond to the dof types in the subsidiary block preconditioner
2645  unsigned n_sub_dof_types=2;
2646  Vector<unsigned> dof_map(n_sub_dof_types);
2647  dof_map[0]=0;
2648  dof_map[1]=1;
2649  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
2650 
2651  // Perform setup. Note that because the subsidiary
2652  // preconditioner is a block preconditioner itself it is given
2653  // the pointer to the "full" matrix
2654  block_prec_pt->setup(this->matrix_pt());
2655  }
2656 
2657  // Second subsidiary precond is a block triangular preconditioner
2658  {
2659  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
2661  Second_subsidiary_preconditioner_pt=block_prec_pt;
2662 
2663  // Set mesh
2664  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
2665 
2666  // Turn it into a subsidiary preconditioner, declaring which
2667  // of the five dof types in the present (master) preconditioner
2668  // correspond to the dof types in the subsidiary block preconditioner
2669  unsigned n_sub_dof_types=3;
2670  Vector<unsigned> dof_map(n_sub_dof_types);
2671  dof_map[0]=2;
2672  dof_map[1]=3;
2673  dof_map[2]=4;
2674  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
2675 
2676  // Perform setup. Note that because the subsidiary
2677  // preconditioner is a block preconditioner itself it is given
2678  // the pointer to the "full" matrix
2679  block_prec_pt->setup(this->matrix_pt());
2680  }
2681 
2682  // Next setup the off diagonal mat vec operators:
2683  {
2684  // Get the block
2685  CRDoubleMatrix block_matrix = this->get_block(0,1);
2686 
2687  // Create matrix vector product operator
2688  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
2689 
2690  // Setup: Final argument indicates block column in the present
2691  // block preconditioner (which views the system matrix as comprising
2692  // 2x2 blocks).
2693  unsigned block_column_index=1;
2694  this->setup_matrix_vector_product(
2695  Off_diagonal_matrix_vector_product_pt,&block_matrix,block_column_index);
2696 
2697  // Extracted block can now go out of scope since the matrix vector
2698  // product retains whatever information it needs
2699  }
2700 
2701  }
2702 
2703 
2704  //=============================================================================
2710  //=============================================================================
2711  template<typename MATRIX>
2714  {
2715  // Now apply the subsidiary block preconditioner that acts on the
2716  // "bottom right" 3x3 sub-system (only!). The subsidiary preconditioner
2717  // will extract the relevant (3x1) "sub-vectors" from the "big" (5x1)
2718  // vector big_r and treat it as the rhs, r, of P z = r
2719  // where P is 3x3 block diagonal.
2720  Second_subsidiary_preconditioner_pt->preconditioner_solve(r,z);
2721 
2722  // Split up rhs vector into sub-vectors, re-arranged to match
2723  // the matrix blocks
2724  DoubleVector r_0;
2725  this->get_block_vector(0,r,r_0);
2726 
2727  DoubleVector z_1;
2728  this->get_block_vector(1,z,z_1);
2729 
2730  // Multiply by (0,1) off diagonal.
2731  DoubleVector temp;
2732  Off_diagonal_matrix_vector_product_pt->multiply(z_1,temp);
2733  r_0 -= temp;
2734 
2735  // Block solve for first diagonal block. Since the associated subsidiary
2736  // preconditioner is a block preconditioner itself, it will extract
2737  // the required (2x1) block rhs from a "big" (5x1) rhs vector, big_r.
2738  // Therefore we first put the actual (2x1) rhs vector block_r_0 into the
2739  // "big" (5x1) vector big_r.
2740  DoubleVector big_r(z.distribution_pt());
2741  this->return_block_vector(0,r_0,big_r);
2742 
2743  // Now apply the subsidiary block preconditioner that acts on the
2744  // "top left" 2x2 sub-system (only!). The subsidiary preconditioner
2745  // will extract the relevant (2x1) "sub-vectors" from the "big" (5x1)
2746  // vector big_r and treat it as the rhs, r, of P z = r
2747  // where P is 2x2 block diagonal. Once the system is solved,
2748  // the result is automatically put back into the appropriate places
2749  // of the "big" (5x1) vector z:
2750  First_subsidiary_preconditioner_pt->preconditioner_solve(big_r,z);
2751 
2752  }
2753 
2754  //==start_of_clean_up_for_two_plus_three_upper_triangular_with_replace========
2756  //============================================================================
2757  template<typename MATRIX>
2760  {
2761  // Clean up subsidiary preconditioners.
2762  if(First_subsidiary_preconditioner_pt!=0)
2763  {
2764  delete First_subsidiary_preconditioner_pt;
2765  First_subsidiary_preconditioner_pt = 0;
2766  }
2767  if(Second_subsidiary_preconditioner_pt!=0)
2768  {
2769  delete Second_subsidiary_preconditioner_pt;
2770  Second_subsidiary_preconditioner_pt = 0;
2771  }
2772 
2773  // Clean up the replacement matricies.
2774  for(unsigned i=0,ni=Replacement_matrix_pt.nrow();i<ni;i++)
2775  {
2776  for(unsigned j=0,nj=Replacement_matrix_pt.ncol();j<nj;j++)
2777  {
2778  if(Replacement_matrix_pt(i,j)!=0)
2779  {
2780  delete Replacement_matrix_pt(i,j);
2781  Replacement_matrix_pt(i,j)=0;
2782  }
2783  } // End loop over j.
2784  } // End loop over i.
2785 
2786  // Clean up the off diag matrix products.
2787  if(Off_diagonal_matrix_vector_product_pt != 0)
2788  {
2789  delete Off_diagonal_matrix_vector_product_pt;
2790  Off_diagonal_matrix_vector_product_pt = 0;
2791  }
2792  } // End of clean_up_my_memory function.
2793 
2797 
2798 
2799 //==================start_of_coarse_two_plus_two_plus_one_class================
2804 //=============================================================================
2805  template<typename MATRIX>
2807  public BlockPreconditioner<MATRIX>
2808  {
2809 
2810  public :
2811 
2814  BlockPreconditioner<MATRIX>(),
2818  {
2820  } // end_of_constructor
2821 
2822 
2825  {
2826  this->clean_up_my_memory();
2827  }
2828 
2830  virtual void clean_up_my_memory();
2831 
2834  (const CoarseTwoPlusTwoPlusOne&)
2835  {
2837  "CoarseTwoPlusTwoPlusOne");
2838  }
2839 
2841  void operator=(const
2843  {
2845  "CoarseTwoPlusTwoPlusOne");
2846  }
2847 
2850 
2852  virtual void setup();
2853 
2855  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
2856  {
2857  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
2858  }
2859 
2860  private :
2861 
2865 
2869 
2870  // Matrix of pointers to replacement matrix blocks
2872 
2875 
2879  };
2880 
2881  //===============start_of_setup_for_coarse_two_plus_two_plus_one=============
2883  //===========================================================================
2884  template<typename MATRIX>
2886  {
2887  // Clean up memory
2888  this->clean_up_my_memory();
2889 
2890 #ifdef PARANOID
2891  if (Multi_poisson_mesh_pt == 0)
2892  {
2893  std::stringstream err;
2894  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
2895  throw OomphLibError(err.str(),
2898  }
2899 #endif
2900 
2901  // The preconditioner works with one mesh; set it!
2902  this->set_nmesh(1);
2903  this->set_mesh(0,Multi_poisson_mesh_pt);
2904 
2905  // This preconditioner only works for 5 dof types
2906  unsigned n_dof_types = this->ndof_types();
2907 #ifdef PARANOID
2908  if (n_dof_types!=5)
2909  {
2910  std::stringstream tmp;
2911  tmp << "This preconditioner only works for problems with 5 dof types\n"
2912  << "Yours has " << n_dof_types;
2913  throw OomphLibError(tmp.str(),
2916  }
2917 #endif
2918 
2919 
2920  // Call block setup with the Vector [0,0,1,1,1] to:
2921  // Merge DOF types 0 and 1 into block type 0.
2922  // Merge DOF types 2, 3 and 4 into block type 1.
2923  Vector<unsigned> dof_to_block_map(n_dof_types,0);
2924  dof_to_block_map[0] = 0;
2925  dof_to_block_map[1] = 0;
2926  dof_to_block_map[2] = 1;
2927  dof_to_block_map[3] = 1;
2928  dof_to_block_map[4] = 1;
2929  this->block_setup(dof_to_block_map);
2930 
2931 
2932  // Replace all the off-diagonal DOF blocks.
2933  Replacement_matrix_pt.resize(n_dof_types,n_dof_types,0);
2934  for(unsigned i=0;i<n_dof_types;i++)
2935  {
2936  for(unsigned j=0;j<n_dof_types;j++)
2937  {
2938  if(i!=j)
2939  {
2940  // Get the DOF block's (row!) distribution.
2941  LinearAlgebraDistribution* dof_block_dist_pt=
2942  this->dof_block_distribution_pt(i);
2943 
2944  // Number of rows in DOF block matrix (i,j).
2945  const unsigned long dof_block_nrow = dof_block_dist_pt->nrow_local();
2946 
2947  // Number of columns in block matrix (i,j) is the same as the number
2948  // of rows in block matrix (j,i).
2949  // We use the actual nrow, not the local one here as this block may
2950  // need to be gotten from another processor.
2951  const unsigned long dof_block_ncol
2952  = this->dof_block_distribution_pt(j)->nrow();
2953 
2954  // Storage for replacement matrices:
2955  // Values
2956  Vector<double> replacement_value(0);
2957  // Column index
2958  Vector<int> replacement_column_index(0);
2959  // Row start
2960  Vector<int> replacement_row_start;
2961 
2962  // Need one row start per row, and one for the nnz, all of which are 0.
2963  replacement_row_start.resize(dof_block_nrow+1,0);
2964 
2965  Replacement_matrix_pt(i,j)=
2966  new CRDoubleMatrix(dof_block_dist_pt, dof_block_ncol,
2967  replacement_value,
2968  replacement_column_index, replacement_row_start);
2969 
2970  // Replace.
2971  this->set_replacement_dof_block(i,j,Replacement_matrix_pt(i,j));
2972 
2973  }// End of if
2974  }// End of j loop.
2975  }// End of i loop.
2976 
2977  // Create the subsidiary preconditioners
2978  //--------------------------------------
2979  {
2980  // First subsidiary precond is a block diagonal preconditioner itself.
2981  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
2983  First_subsidiary_preconditioner_pt=block_prec_pt;
2984 
2985  // Set mesh
2986  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
2987 
2988  // Turn first_sub into a subsidiary preconditioner, declaring which
2989  // of the five dof types in the present (master) preconditioner
2990  // correspond to the dof types in the subsidiary block preconditioner
2991  const unsigned n_sub_dof_types=2;
2992  Vector<unsigned> dof_map(n_sub_dof_types);
2993  dof_map[0]=0;
2994  dof_map[1]=1;
2995  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
2996 
2997  // Perform setup. Note that because the subsidiary
2998  // preconditioner is a block preconditioner itself it is given
2999  // the pointer to the "full" matrix
3000  block_prec_pt->setup(this->matrix_pt());
3001  }
3002 
3003  // Second subsidiary preconditioner is also a block preconditioner
3004  {
3005  SimpleTwoDofOnly<CRDoubleMatrix>* block_prec_pt=
3007  Second_subsidiary_preconditioner_pt=block_prec_pt;
3008 
3009  // Set mesh
3010  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
3011 
3012  // This is the usual mapping between the subsidiary and master dof types.
3013  Vector<unsigned> dof_map(3);
3014  dof_map[0]=2;
3015  dof_map[1]=3;
3016  dof_map[2]=4;
3017 
3018  // The subsidiary block preconditioner SimpleTwoDofOnly accepts only two
3019  // dof types. We therefore have to "coarsen" the 3 dof types into two
3020  // by specifying the vector of vectors doftype_coarsening whose
3021  // entries are to be interpreted as
3022  //
3023  // doftype_coarsening[coarsened_dof_type][i]=dof_type
3024  //
3025  // where i ranges from 0 to the number of dof types (minus one, because
3026  // of the zero-based indexing...) that are to be
3027  // combined/coarsened into dof type dof_type_in_coarsed_block_preconditioner
3028 
3029 
3030  // Number of dof types the subsidiary block preconditioner expects.
3031  const unsigned n_sub_dof_types=2;
3032  Vector<Vector<unsigned> > doftype_coarsening(n_sub_dof_types);
3033 
3034  // Subsidiary dof type 0 contains 2 dof types.
3035  doftype_coarsening[0].resize(2);
3036 
3037  // Coarsen subsidiary dof types 0 and 1 into subsidiary dof type 0.
3038  doftype_coarsening[0][0]=0;
3039  doftype_coarsening[0][1]=1;
3040 
3041  // Subsidiary dof type 1 contains 1 dof types.
3042  doftype_coarsening[1].resize(1);
3043 
3044  // Subsidiary Dof type 1 contains subsidiary dof type 2.
3045  doftype_coarsening[1][0]=2;
3046 
3047  // Turn into subdiary preconditioner
3048  block_prec_pt->
3049  turn_into_subsidiary_block_preconditioner(this,dof_map,
3050  doftype_coarsening);
3051 
3052  // Perform setup. Note that because the subsidiary
3053  // preconditioner is a block preconditioner itself it is given
3054  // the pointer to the "full" matrix
3055  block_prec_pt->setup(this->matrix_pt());
3056  }
3057 
3058 
3059  // Set up off diagonal matrix vector product
3060  {
3061  // Get the off diagonal block.
3062  CRDoubleMatrix block_matrix = this->get_block(0,1);
3063 
3064  // Create matrix vector product operator
3065  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
3066 
3067  // Setup: Final argument indicates block column in the present
3068  // block preconditioner (which views the system matrix as comprising
3069  // 2x2 blocks).
3070  unsigned block_column_index=1;
3071  this->setup_matrix_vector_product(
3072  Off_diagonal_matrix_vector_product_pt,&block_matrix,block_column_index);
3073 
3074  // extracted block can now go out of scope; the matrix vector product
3075  // retains its own (deep) copy.
3076  }
3077 
3078  }// End of setup
3079 
3080 
3081  //=============================================================================
3086  //=============================================================================
3087  template<typename MATRIX>
3090  {
3091  // Now apply the subsidiary block preconditioner that acts on the
3092  // "bottom right" 3x3 sub-system (only!). The subsidiary preconditioner
3093  // will extract the relevant (3x1) "sub-vectors" from the "big" (5x1)
3094  // vector big_r and treat it as the rhs, r, of P z = r
3095  // where P is 3x3 block diagonal.
3096  Second_subsidiary_preconditioner_pt->preconditioner_solve(r,z);
3097 
3098  // Get the entries from r corresponding to matrix block 0.
3099  DoubleVector r_0;
3100  this->get_block_vector(0,r,r_0);
3101 
3102  // Get the entries from z corresponding to matrix block 0.
3103  DoubleVector z_1;
3104  this->get_block_vector(1,z,z_1);
3105 
3106  // Multiply by off diagonal block and subtract from RHS.
3107  DoubleVector temp;
3108  Off_diagonal_matrix_vector_product_pt->multiply(z_1,temp);
3109  r_0 -= temp;
3110 
3111  // Block solve for first diagonal block. Since the associated subsidiary
3112  // preconditioner is a block preconditioner itself, it will extract
3113  // the required (2x1) block rhs from a "big" (5x1) rhs vector, big_r.
3114  // Therefore we first put the actual (2x1) rhs vector block_r_0 into the
3115  // "big" (5x1) vector big_r.
3116  DoubleVector big_r(z.distribution_pt());
3117 
3118  this->return_block_vector(0,r_0,big_r);
3119 
3120  // Now apply the subsidiary block preconditioner that acts on the
3121  // "top left" 2x2 sub-system (only!). The subsidiary preconditioner
3122  // will extract the relevant (2x1) "sub-vectors" from the "big" (5x1)
3123  // vector big_r and treat it as the rhs, r, of P z = r
3124  // where P is 2x2 block diagonal. Once the system is solved,
3125  // the result is automatically put back into the appropriate places
3126  // of the "big" (5x1) vector z:
3127  First_subsidiary_preconditioner_pt->preconditioner_solve(big_r,z);
3128  }// End of solve
3129 
3130  //=============start_of_clean_up_for_coarse_one_plus_two_plus_two===========
3132 //===========================================================================
3133  template<typename MATRIX>
3136  {
3137  // Delete diagonal preconditioners (approximate solvers)
3138  if(First_subsidiary_preconditioner_pt!=0)
3139  {
3140  delete First_subsidiary_preconditioner_pt;
3141  First_subsidiary_preconditioner_pt = 0;
3142  }
3143  if(Second_subsidiary_preconditioner_pt!=0)
3144  {
3145  delete Second_subsidiary_preconditioner_pt;
3146  Second_subsidiary_preconditioner_pt = 0;
3147  }
3148 
3149  // Clean up the replacement matricies.
3150  for(unsigned i=0,ni=Replacement_matrix_pt.nrow();i<ni;i++)
3151  {
3152  for(unsigned j=0,nj=Replacement_matrix_pt.ncol();j<nj;j++)
3153  {
3154  if(Replacement_matrix_pt(i,j)!=0)
3155  {
3156  delete Replacement_matrix_pt(i,j);
3157  Replacement_matrix_pt(i,j)=0;
3158  }
3159  } // End loop over j.
3160  } // End loop over i.
3161 
3162  // Kill matrix vector product
3163  if(Off_diagonal_matrix_vector_product_pt!= 0)
3164  {
3165  delete Off_diagonal_matrix_vector_product_pt;
3166  Off_diagonal_matrix_vector_product_pt = 0;
3167  }
3168 
3169  } // End of clean_up_my_memory function.
3170 
3174 
3175 
3176 
3177 //==================start_of_coarse_two_plus_two_plus_one_class================
3183 //=============================================================================
3184  template<typename MATRIX>
3186  public BlockPreconditioner<MATRIX>
3187  {
3188 
3189  public :
3190 
3193  BlockPreconditioner<MATRIX>(),
3197  {
3199  } // end_of_constructor
3200 
3201 
3204  {
3205  this->clean_up_my_memory();
3206  }
3207 
3209  virtual void clean_up_my_memory();
3210 
3213  (const OnePlusFourWithTwoCoarse&)
3214  {
3216  "OnePlusFourWithTwoCoarse");
3217  }
3218 
3220  void operator=(const
3222  {
3224  "OnePlusFourWithTwoCoarse");
3225  }
3226 
3229 
3231  virtual void setup();
3232 
3234  void set_multi_poisson_mesh(Mesh* multi_poisson_mesh_pt)
3235  {
3236  Multi_poisson_mesh_pt=multi_poisson_mesh_pt;
3237  }
3238 
3239  private :
3240 
3244 
3248 
3249  // Matrix of pointers to replacement matrx blocks
3251 
3254 
3258 
3259  };
3260 
3261  //===============start_of_setup_for_coarse_two_plus_two_plus_one=============
3263  //===========================================================================
3264  template<typename MATRIX>
3266  {
3267  // Clean up memory
3268  this->clean_up_my_memory();
3269 
3270 #ifdef PARANOID
3271  if (Multi_poisson_mesh_pt == 0)
3272  {
3273  std::stringstream err;
3274  err << "Please set pointer to mesh using set_multi_poisson_mesh(...).\n";
3275  throw OomphLibError(err.str(),
3278  }
3279 #endif
3280 
3281  // The preconditioner works with one mesh; set it!
3282  this->set_nmesh(1);
3283  this->set_mesh(0,Multi_poisson_mesh_pt);
3284 
3285  // This preconditioner only works for 5 dof types
3286  unsigned n_dof_types = this->ndof_types();
3287 #ifdef PARANOID
3288  if (n_dof_types!=5)
3289  {
3290  std::stringstream tmp;
3291  tmp << "This preconditioner only works for problems with 5 dof types\n"
3292  << "Yours has " << n_dof_types;
3293  throw OomphLibError(tmp.str(),
3296  }
3297 #endif
3298 
3299  // Combine into two major blocks, one containing dof type 0, the
3300  // final one dof types 1-4. In general we want:
3301  // dof_to_block_map[dof_type] = block type
3302  Vector<unsigned> dof_to_block_map(n_dof_types,0);
3303  dof_to_block_map[0] = 0;
3304  dof_to_block_map[1] = 1;
3305  dof_to_block_map[2] = 1;
3306  dof_to_block_map[3] = 1;
3307  dof_to_block_map[4] = 1;
3308  this->block_setup(dof_to_block_map);
3309 
3310  // Replace all the off-diagonal DOF blocks.
3311  Replacement_matrix_pt.resize(n_dof_types,n_dof_types,0);
3312  for(unsigned i=0;i<n_dof_types;i++)
3313  {
3314  for(unsigned j=0;j<n_dof_types;j++)
3315  {
3316  if(i!=j)
3317  {
3318  // Get the DOF block's (row!) distribution.
3319  LinearAlgebraDistribution* dof_block_dist_pt=
3320  this->dof_block_distribution_pt(i);
3321 
3322  // Number of rows in DOF block matrix (i,j).
3323  const unsigned long dof_block_nrow = dof_block_dist_pt->nrow_local();
3324 
3325  // Number of columns in block matrix (i,j) is the same as the number
3326  // of rows in block matrix (j,i).
3327  // We use the actual nrow, not the local one here as this block may
3328  // need to be gotten from another processor.
3329  const unsigned long dof_block_ncol
3330  = this->dof_block_distribution_pt(j)->nrow();
3331 
3332  // Storage for replacement matrices:
3333  // Values
3334  Vector<double> replacement_value(0);
3335  // Column index
3336  Vector<int> replacement_column_index(0);
3337  // Row start
3338  Vector<int> replacement_row_start;
3339 
3340  // Need one row start per row, and one for the nnz, all of which are 0.
3341  replacement_row_start.resize(dof_block_nrow+1,0);
3342 
3343  Replacement_matrix_pt(i,j)=
3344  new CRDoubleMatrix(dof_block_dist_pt, dof_block_ncol, replacement_value,
3345  replacement_column_index, replacement_row_start);
3346 
3347  // Replace.
3348  this->set_replacement_dof_block(i,j,Replacement_matrix_pt(i,j));
3349  }// End of if
3350  }// End of j loop.
3351  }// End of i loop.
3352 
3353  // Create the subsidiary preconditioners
3354  //--------------------------------------
3355 
3356  {
3357  // First subsidiary precond is a block diagonal preconditioner itself.
3358  // Put in owns cope so block_prec_pt goes out of scope.
3359  UpperTriangular<CRDoubleMatrix>* block_prec_pt=
3361  First_subsidiary_preconditioner_pt=block_prec_pt;
3362 
3363  // Set mesh
3364  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
3365 
3366  // Turn first_sub into a subsidiary preconditioner, declaring which
3367  // of the five dof types in the present (master) preconditioner
3368  // correspond to the dof types in the subsidiary block preconditioner
3369  unsigned n_sub_dof_types=1;
3370  Vector<unsigned> dof_map(n_sub_dof_types);
3371  dof_map[0]=0;
3372  block_prec_pt->turn_into_subsidiary_block_preconditioner(this,dof_map);
3373 
3374  // Perform setup. Note that because the subsidiary
3375  // preconditioner is a block preconditioner itself it is given
3376  // the pointer to the "full" matrix
3377  block_prec_pt->setup(this->matrix_pt());
3378  }
3379 
3380 
3381  // Second subsidiary precond is a block diagonal preconditioner itself
3382  // This preconditioner only accepts two DOF types, it then coarsen these
3383  // two dof types to use a block preconditioner which accepts only one DOF
3384  // type.
3385  CoarseTwoIntoOne<CRDoubleMatrix>* block_prec_pt=
3387  Second_subsidiary_preconditioner_pt=block_prec_pt;
3388 
3389  // Set mesh
3390  block_prec_pt->set_multi_poisson_mesh(Multi_poisson_mesh_pt);
3391 
3392  // This is the usual dof map between subsidiary and master dof types.
3393  Vector<unsigned> dof_map(4);
3394  dof_map[0]=1;
3395  dof_map[1]=2;
3396  dof_map[2]=3;
3397  dof_map[3]=4;
3398 
3399 
3400  // The subsidiary block preconditioner CoarseTwoIntoOne accepts only two
3401  // dof types. To use this preconditioner on the remaining 4 dof types,
3402  // we coarsen the 4 dof types into 2 dof types
3403  // by specifying the vector of vectors doftype_coarsening whose
3404  // entries are to be interpreted as
3405  //
3406  // doftype_coarsening[coarsened_dof_type][i]=dof_type
3407  //
3408  // where i ranges from 0 to the number of dof types (minus one, because
3409  // of the zero-based indexing...) that are to be
3410  // combined/coarsened into dof type dof_type_in_coarsed_block_preconditioner
3411 
3412  // Number of dof types the subsidiary block preconditioner expects.
3413  const unsigned n_sub_dof_types=2;
3414  Vector<Vector<unsigned> > doftype_coarsening(n_sub_dof_types);
3415 
3416  // Subsidiary dof type 0 contains 2 dof types.
3417  doftype_coarsening[0].resize(2);
3418 
3419  // Coarsen subsidiary dof types 0 and 1 into subsidiary dof type 0.
3420  doftype_coarsening[0][0]=0;
3421  doftype_coarsening[0][1]=1;
3422 
3423  // Subsidiary dof type 1 contains 2 dof types.
3424  doftype_coarsening[1].resize(2);
3425 
3426  // Coarsen subsidiary dof types 0 and 1 into subsidiary dof type 1.
3427  doftype_coarsening[1][0]=2;
3428  doftype_coarsening[1][1]=3;
3429 
3430  // Turn the block preconditioner into a subsidiary block preconditioner.
3431  block_prec_pt->
3432  turn_into_subsidiary_block_preconditioner(this,dof_map,
3433  doftype_coarsening);
3434 
3435  // Perform setup. Note that because the subsidiary
3436  // preconditioner is a block preconditioner itself it is given
3437  // the pointer to the "full" matrix
3438  block_prec_pt->setup(this->matrix_pt());
3439 
3440 
3441  // Set up off diagonal matrix vector product
3442  {
3443  // Get the block
3444  CRDoubleMatrix block_matrix = this->get_block(0,1);
3445 
3446  // Create matrix vector product operator
3447  Off_diagonal_matrix_vector_product_pt = new MatrixVectorProduct;
3448 
3449  // Setup: Final argument indicates block column in the present
3450  // block preconditioner (which views the system matrix as comprising
3451  // 2x2 blocks).
3452  unsigned block_column_index=1;
3453  this->setup_matrix_vector_product(
3454  Off_diagonal_matrix_vector_product_pt,&block_matrix, block_column_index);
3455  }
3456 
3457  }// End of setup
3458 
3459 
3460  //=============================================================================
3466  //=============================================================================
3467  template<typename MATRIX>
3470  {
3471  // Now apply the subsidiary block preconditioner that acts on the
3472  // "bottom right" 4x4 sub-system (only!). The subsidiary preconditioner
3473  // will extract the relevant (4x1) "sub-vectors" from the "big" (5x1)
3474  // vector big_r and treat it as the rhs, r, of P z = r
3475  // where P is 4x4 block diagonal.
3476  Second_subsidiary_preconditioner_pt->preconditioner_solve(r,z);
3477 
3478  // Split up rhs vector into sub-vectors, re-arranged to match
3479  // the matrix blocks
3480  DoubleVector r_0;
3481  this->get_block_vector(0,r,r_0);
3482 
3483  DoubleVector z_1;
3484  this->get_block_vector(1,z,z_1);
3485 
3486  // Multiply by (0,1) off diagonal.
3487  DoubleVector temp;
3488  Off_diagonal_matrix_vector_product_pt->multiply(z_1,temp);
3489  r_0 -= temp;
3490 
3491  // Block solve for first diagonal block. Since the associated subsidiary
3492  // preconditioner is a block preconditioner itself, it will extract
3493  // the required (1x1) block rhs from a "big" (5x1) rhs vector, big_r.
3494  // Therefore we first put the actual (1x1) rhs vector block_r_0 into the
3495  // "big" (5x1) vector big_r.
3496  DoubleVector big_r(z.distribution_pt());
3497 
3498  this->return_block_vector(0,r_0,big_r);
3499  // Now apply the subsidiary block preconditioner that acts on the
3500  // "top left" 1x1 sub-system (only!). The subsidiary preconditioner
3501  // will extract the relevant (1x1) "sub-vectors" from the "big" (5x1)
3502  // vector big_r and treat it as the rhs, r, of P z = r
3503  // where P is 1x1 block diagonal. Once the system is solved,
3504  // the result is automatically put back into the appropriate places
3505  // of the "big" (5x1) vector z:
3506  First_subsidiary_preconditioner_pt->preconditioner_solve(big_r,z);
3507  }// End of solve
3508 
3509  //=============start_of_clean_up_for_coarse_one_plus_two_plus_two===========
3511 //===========================================================================
3512  template<typename MATRIX>
3515  {
3516  // Delete diagonal preconditioners (approximate solvers)
3517  if(First_subsidiary_preconditioner_pt!=0)
3518  {
3519  delete First_subsidiary_preconditioner_pt;
3520  First_subsidiary_preconditioner_pt = 0;
3521  }
3522  if(Second_subsidiary_preconditioner_pt!=0)
3523  {
3524  delete Second_subsidiary_preconditioner_pt;
3525  Second_subsidiary_preconditioner_pt = 0;
3526  }
3527 
3528  // Clean up the replacement matrices.
3529  for(unsigned i=0,ni=Replacement_matrix_pt.nrow();i<ni;i++)
3530  {
3531  for(unsigned j=0,nj=Replacement_matrix_pt.ncol();j<nj;j++)
3532  {
3533  if(Replacement_matrix_pt(i,j)!=0)
3534  {
3535  delete Replacement_matrix_pt(i,j);
3536  Replacement_matrix_pt(i,j)=0;
3537  }
3538  } // End loop over j.
3539  } // End loop over i.
3540 
3541  // Kill off diagonal matrix vector product
3542  if(Off_diagonal_matrix_vector_product_pt!= 0)
3543  {
3544  delete Off_diagonal_matrix_vector_product_pt;
3545  Off_diagonal_matrix_vector_product_pt = 0;
3546  }
3547 
3548  } // End of clean_up_my_memory function.
3549 
3550 
3551 
3552 
3556 
3557 
3558 }
3559 #endif
int i
Definition: BiCGSTAB_step_by_step.cpp:9
m m block(1, 0, 2, 2)<< 4
Definition: block_preconditioner.h:422
void turn_into_subsidiary_block_preconditioner(BlockPreconditioner< MATRIX > *master_block_prec_pt, const Vector< unsigned > &doftype_in_master_preconditioner_coarse)
Definition: block_preconditioner.cc:2376
Definition: matrices.h:888
Definition: multi_poisson_block_preconditioners.h:634
CoarseTwoIntoOne(const CoarseTwoIntoOne &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:656
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:697
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Definition: multi_poisson_block_preconditioners.h:820
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:704
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:832
CoarseTwoIntoOne()
Constructor for CoarseTwoIntoOne.
Definition: multi_poisson_block_preconditioners.h:639
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:685
void operator=(const CoarseTwoIntoOne &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:662
Preconditioner * Subsidiary_preconditioner_pt
Pointer to the preconditioners/inexact solvers.
Definition: multi_poisson_block_preconditioners.h:693
~CoarseTwoIntoOne()
Destructor - delete the diagonal solvers (subsidiary preconditioners)
Definition: multi_poisson_block_preconditioners.h:647
Definition: multi_poisson_block_preconditioners.h:2808
DenseMatrix< CRDoubleMatrix * > Replacement_matrix_pt
Definition: multi_poisson_block_preconditioners.h:2871
void operator=(const CoarseTwoPlusTwoPlusOne &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:2841
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:3135
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return z such that P z = r.
Definition: multi_poisson_block_preconditioners.h:3089
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:2878
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:2864
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:2855
CoarseTwoPlusTwoPlusOne(const CoarseTwoPlusTwoPlusOne &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:2834
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:2868
~CoarseTwoPlusTwoPlusOne()
Destructor - delete the diagonal solvers (subsidiary preconditioners)
Definition: multi_poisson_block_preconditioners.h:2824
CoarseTwoPlusTwoPlusOne()
Constructor for CoarseTwoPlusTwoPlusOne.
Definition: multi_poisson_block_preconditioners.h:2813
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Matrix vector product operator.
Definition: multi_poisson_block_preconditioners.h:2874
virtual void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:2885
Definition: matrices.h:386
Definition: multi_poisson_block_preconditioners.h:53
Diagonal(const Diagonal &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:75
Diagonal()
Constructor for Diagonal preconditioner.
Definition: multi_poisson_block_preconditioners.h:58
~Diagonal()
Definition: multi_poisson_block_preconditioners.h:66
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:210
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:120
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return solution of P z = r.
Definition: multi_poisson_block_preconditioners.h:184
void operator=(const Diagonal &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:81
Vector< Preconditioner * > Diagonal_block_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:108
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:99
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:112
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
Definition: linear_algebra_distribution.h:457
Definition: double_vector.h:58
Definition: linear_algebra_distribution.h:64
unsigned nrow_local() const
Definition: linear_algebra_distribution.h:193
Definition: matrix_vector_product.h:51
Definition: mesh.h:67
Definition: multi_poisson_block_preconditioners.h:3187
DenseMatrix< CRDoubleMatrix * > Replacement_matrix_pt
Definition: multi_poisson_block_preconditioners.h:3250
OnePlusFourWithTwoCoarse(const OnePlusFourWithTwoCoarse &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:3213
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:3243
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:3257
OnePlusFourWithTwoCoarse()
Constructor for OnePlusFourWithTwoCoarse.
Definition: multi_poisson_block_preconditioners.h:3192
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:3234
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:3247
virtual void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:3265
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return z such that P z = r.
Definition: multi_poisson_block_preconditioners.h:3469
void operator=(const OnePlusFourWithTwoCoarse &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:3220
~OnePlusFourWithTwoCoarse()
Destructor - delete the diagonal solvers (subsidiary preconditioners)
Definition: multi_poisson_block_preconditioners.h:3203
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Matrix vector product operators for the off diagonal.
Definition: multi_poisson_block_preconditioners.h:3253
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:3514
Definition: oomph_definitions.h:222
Definition: preconditioner.h:54
virtual void setup()=0
Definition: multi_poisson_block_preconditioners.h:448
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:606
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return solution of P z = r.
Definition: multi_poisson_block_preconditioners.h:588
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:505
~SimpleOneDofOnly()
Destructor - delete the diagonal solvers (subsidiary preconditioners)
Definition: multi_poisson_block_preconditioners.h:461
void operator=(const SimpleOneDofOnly &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:476
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:512
Preconditioner * Subsidiary_preconditioner_pt
Pointer to the preconditioners/inexact solver.
Definition: multi_poisson_block_preconditioners.h:501
SimpleOneDofOnly()
Constructor for SimpleOneDofOnly.
Definition: multi_poisson_block_preconditioners.h:453
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:493
SimpleOneDofOnly(const SimpleOneDofOnly &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:470
Definition: multi_poisson_block_preconditioners.h:239
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return solution of P z = r.
Definition: multi_poisson_block_preconditioners.h:393
virtual void clean_up_my_memory()
Clean up the memory.
Definition: multi_poisson_block_preconditioners.h:419
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:303
Vector< Preconditioner * > Diagonal_block_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:291
SimpleTwoDofOnly()
Constructor for SimpleTwoDofOnly.
Definition: multi_poisson_block_preconditioners.h:244
SimpleTwoDofOnly(const SimpleTwoDofOnly &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:260
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:295
~SimpleTwoDofOnly()
Destructor - clean up memory.
Definition: multi_poisson_block_preconditioners.h:251
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:282
void operator=(const SimpleTwoDofOnly &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:266
An interface to allow SuperLU to be used as an (exact) Preconditioner.
Definition: SuperLU_preconditioner.h:40
Definition: multi_poisson_block_preconditioners.h:1829
void operator=(const TwoPlusOneUpperTriangularPreconditioner &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:1862
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Matrix vector product operators for the off diagonals.
Definition: multi_poisson_block_preconditioners.h:1894
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1887
TwoPlusOneUpperTriangularPreconditioner(const TwoPlusOneUpperTriangularPreconditioner &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:1856
~TwoPlusOneUpperTriangularPreconditioner()
Destructor - delete the diagonal solvers (subsidiary preconditioners)
Definition: multi_poisson_block_preconditioners.h:1845
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:1898
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1891
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return z such that P z = r.
Definition: multi_poisson_block_preconditioners.h:2032
virtual void clean_up_my_memory()
Cleanup function.
Definition: multi_poisson_block_preconditioners.h:2078
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:1906
TwoPlusOneUpperTriangularPreconditioner()
Constructor for TwoPlusOneUpperTriangularPreconditioner.
Definition: multi_poisson_block_preconditioners.h:1834
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:1878
Definition: multi_poisson_block_preconditioners.h:1534
TwoPlusThreeUpperTriangularWithOneLevelSubsidiary()
Constructor.
Definition: multi_poisson_block_preconditioners.h:1539
void operator=(const TwoPlusThreeUpperTriangularWithOneLevelSubsidiary &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:1566
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:1584
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1600
void clean_up_my_memory()
Clean up the memory.
Definition: multi_poisson_block_preconditioners.h:1792
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Pointer to matrix vector product operators for the off diagonal block.
Definition: multi_poisson_block_preconditioners.h:1592
TwoPlusThreeUpperTriangularWithOneLevelSubsidiary(const TwoPlusThreeUpperTriangularWithOneLevelSubsidiary &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:1559
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1596
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
Definition: multi_poisson_block_preconditioners.h:1735
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:1604
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:1612
virtual ~TwoPlusThreeUpperTriangularWithOneLevelSubsidiary()
Destructor - delete the preconditioner matrices.
Definition: multi_poisson_block_preconditioners.h:1549
Definition: multi_poisson_block_preconditioners.h:2416
DenseMatrix< CRDoubleMatrix * > Replacement_matrix_pt
Definition: multi_poisson_block_preconditioners.h:2482
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:2495
virtual void clean_up_my_memory()
Clean up the memory.
Definition: multi_poisson_block_preconditioners.h:2759
void operator=(const TwoPlusThreeUpperTriangularWithReplace &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:2449
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return z such that P z = r.
Definition: multi_poisson_block_preconditioners.h:2713
TwoPlusThreeUpperTriangularWithReplace(const TwoPlusThreeUpperTriangularWithReplace &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:2442
TwoPlusThreeUpperTriangularWithReplace()
Constructor for TwoPlusThreeUpperTriangularWithReplace.
Definition: multi_poisson_block_preconditioners.h:2421
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:2475
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:2462
~TwoPlusThreeUpperTriangularWithReplace()
Destructor clean up memory.
Definition: multi_poisson_block_preconditioners.h:2432
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:2486
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Definition: multi_poisson_block_preconditioners.h:2479
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:2471
Definition: multi_poisson_block_preconditioners.h:2110
virtual ~TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary()
Destructor - delete the preconditioner matrices.
Definition: multi_poisson_block_preconditioners.h:2125
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:2375
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:2180
void operator=(const TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:2142
TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary(const TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:2135
TwoPlusThreeUpperTriangularWithTwoLevelSubsidiary()
Constructor.
Definition: multi_poisson_block_preconditioners.h:2115
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:2160
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
Definition: multi_poisson_block_preconditioners.h:2323
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:2172
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Pointer to matrix vector product operator.
Definition: multi_poisson_block_preconditioners.h:2168
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:2188
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:2176
Definition: multi_poisson_block_preconditioners.h:1290
void operator=(const TwoPlusThreeUpperTriangular &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:1320
MatrixVectorProduct * Off_diagonal_matrix_vector_product_pt
Pointer to matrix vector product operator for the single off diagonals.
Definition: multi_poisson_block_preconditioners.h:1344
TwoPlusThreeUpperTriangular(const TwoPlusThreeUpperTriangular &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:1314
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1348
virtual ~TwoPlusThreeUpperTriangular()
Destructor - delete the preconditioner matrices.
Definition: multi_poisson_block_preconditioners.h:1305
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:1356
TwoPlusThreeUpperTriangular()
Constructor.
Definition: multi_poisson_block_preconditioners.h:1295
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
Definition: multi_poisson_block_preconditioners.h:1463
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:1498
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:1364
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1352
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:1336
Definition: multi_poisson_block_preconditioners.h:1086
virtual void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:1149
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r, i.e. return z such that P z = r.
Definition: multi_poisson_block_preconditioners.h:1234
Preconditioner * Second_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1138
~TwoPlusThree()
Destructor - delete the diagonal solvers (subsidiary preconditioners)
Definition: multi_poisson_block_preconditioners.h:1098
void operator=(const TwoPlusThree &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:1113
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:1142
Preconditioner * First_subsidiary_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:1134
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:1125
TwoPlusThree(const TwoPlusThree &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:1107
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:1263
TwoPlusThree()
Constructor for TwoPlusThree.
Definition: multi_poisson_block_preconditioners.h:1090
Definition: multi_poisson_block_preconditioners.h:854
Vector< Preconditioner * > Block_preconditioner_pt
Definition: multi_poisson_block_preconditioners.h:908
void operator=(const UpperTriangular &)
Broken assignment operator.
Definition: multi_poisson_block_preconditioners.h:880
void setup()
Setup the preconditioner.
Definition: multi_poisson_block_preconditioners.h:920
UpperTriangular(const UpperTriangular &)
Broken copy constructor.
Definition: multi_poisson_block_preconditioners.h:874
virtual void clean_up_my_memory()
clean up the memory
Definition: multi_poisson_block_preconditioners.h:1048
void set_multi_poisson_mesh(Mesh *multi_poisson_mesh_pt)
Specify the mesh that contains multi-poisson elements.
Definition: multi_poisson_block_preconditioners.h:896
Mesh * Multi_poisson_mesh_pt
Definition: multi_poisson_block_preconditioners.h:912
virtual ~UpperTriangular()
Destructor - delete the preconditioner matrices.
Definition: multi_poisson_block_preconditioners.h:865
DenseMatrix< MatrixVectorProduct * > Off_diagonal_matrix_vector_product_pt
Pointers to matrix vector product operators for the off diagonals.
Definition: multi_poisson_block_preconditioners.h:904
UpperTriangular()
Constructor.
Definition: multi_poisson_block_preconditioners.h:859
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
Definition: multi_poisson_block_preconditioners.h:1009
Definition: oomph-lib/src/generic/Vector.h:58
Scalar * y
Definition: level1_cplx_impl.h:128
char char char int int * k
Definition: level2_impl.h:374
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
r
Definition: UniformPSDSelfTest.py:20
void broken_assign(const std::string &class_name)
Issue error message and terminate execution.
Definition: oomph_utilities.cc:195
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
Definition: oomph_utilities.cc:212
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
OomphInfo oomph_info
Definition: oomph_definitions.cc:319
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2