general_purpose_space_time_subsidiary_block_preconditioner.h
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2023 Matthias Heil and Andrew Hazel
7 // LIC//
8 // LIC// This library is free software; you can redistribute it and/or
9 // LIC// modify it under the terms of the GNU Lesser General Public
10 // LIC// License as published by the Free Software Foundation; either
11 // LIC// version 2.1 of the License, or (at your option) any later version.
12 // LIC//
13 // LIC// This library is distributed in the hope that it will be useful,
14 // LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // LIC// Lesser General Public License for more details.
17 // LIC//
18 // LIC// You should have received a copy of the GNU Lesser General Public
19 // LIC// License along with this library; if not, write to the Free Software
20 // LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // LIC// 02110-1301 USA.
22 // LIC//
23 // LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 // LIC//
25 // LIC//====================================================================
26 // Header file for SpaceTimeNavierStokes elements
27 #ifndef OOMPH_GENERAL_PURPOSE_SPACE_TIME_SUBSIDIARY_BLOCK_PRECONDITIONER_HEADER
28 #define OOMPH_GENERAL_PURPOSE_SPACE_TIME_SUBSIDIARY_BLOCK_PRECONDITIONER_HEADER
29 
30 // Config header generated by autoconfig
31 #ifdef HAVE_CONFIG_H
32 #include <oomph-lib-config.h>
33 #endif
34 
35 // oomph-lib includes
38 #include "generic/matrices.h"
39 
40 /// /////////////////////////////////////////////////////////////////////////
41 /// /////////////////////////////////////////////////////////////////////////
42 /// /////////////////////////////////////////////////////////////////////////
43 
44 namespace oomph
45 {
46  //=============================================================================
47  /// General purpose block triangular preconditioner. By default this is
48  /// Upper triangular. Also, by default SuperLUPreconditioner (or
49  /// SuperLUDistPreconditioner) is used to solve the subsidiary systems, but
50  /// other preconditioners can be used by setting them using passing a pointer
51  /// to a function of type SubsidiaryPreconditionerFctPt to the method
52  /// subsidiary_preconditioner_function_pt().
53  //=============================================================================
55  : public BlockPreconditioner<CRDoubleMatrix>
56  {
57  public:
58  /// Constructor. (By default this preconditioner is upper triangular).
61  {
62  // By default, don't store the memory statistics of this preconditioner
64 
65  // Initialise the value of Memory_usage_in_bytes
67 
68  // Flag to indicate that the preconditioner has been setup
69  // previously -- if setup() is called again, data can
70  // be wiped.
72 
73  // By default we use SuperLU for both p and f blocks
76 
77  // Set default preconditioners (inexact solvers) -- they are
78  // members of this class!
81 
82  // Null the momentum block matrix-vector product helper
83  F_mat_vec_pt = 0;
84 
85  // Null the gradient block matrix-vector product helper
86  G_mat_vec_pt = 0;
87  }
88 
89  /// Destructor - delete the preconditioner matrices
91  {
92  // Call the auxiliary clean up function
93  this->clean_up_memory();
94  } // End of ~SpaceTimeNavierStokesSubsidiaryPreconditioner
95 
96  /// Clean up the memory
97  virtual void clean_up_memory()
98  {
99  // If we've actually set the preconditioner up
101  {
102  // Delete matvecs
103  delete F_mat_vec_pt;
104  F_mat_vec_pt = 0;
105 
106  delete G_mat_vec_pt;
107  G_mat_vec_pt = 0;
108 
109  // Delete the momentum block solver
110  delete F_preconditioner_pt;
112 
113  // Delete the Schur complement solver
114  delete P_preconditioner_pt;
116  } // if (Preconditioner_has_been_setup)
117  } // End of clean_up_memory
118 
119  /// Broken copy constructor
122 
123  /// Broken assignment operator
125  delete;
126 
127  /// For some reason we need to remind the compiler that there is
128  /// also a function named setup in the base class.
129  using Preconditioner::setup;
130 
131  /// Setup the preconditioner
132  void setup();
133 
134  /// Apply preconditioner to r
136 
137 
138  /// Document the memory usage
140  {
141  /// Set the appropriate flag to true
143  } // End of enable_doc_memory_usage
144 
145 
146  /// Don't document the memory usage!
148  {
149  /// Set the appropriate flag to false
151  } // End of disable_doc_memory_usage
152 
153 
154  /// Get the memory statistics
156  {
157  // Has the preconditioner even been set up yet?
159  {
160  // Were we meant to compute the statistics?
162  {
163  // Return the appropriate variable value
164  return Memory_usage_in_bytes;
165  }
166  else
167  {
168  // Allocate storage for an output stream
169  std::ostringstream warning_message_stream;
170 
171  // Create a warning message
172  warning_message_stream
173  << "The memory statistics have not been calculated "
174  << "so I'm returning\nthe value zero." << std::endl;
175 
176  // Give the user a warning
177  OomphLibWarning(warning_message_stream.str(),
178  OOMPH_CURRENT_FUNCTION,
179  OOMPH_EXCEPTION_LOCATION);
180 
181  // Return the value zero
182  return 0.0;
183  }
184  }
185  // If the preconditioner hasn't been set up yet
186  else
187  {
188  // Allocate storage for an output stream
189  std::ostringstream warning_message_stream;
190 
191  // Create a warning message
192  warning_message_stream
193  << "The preconditioner hasn't even been set up yet "
194  << "so I'm returning\nthe value zero." << std::endl;
195 
196  // Give the user a warning
197  OomphLibWarning(warning_message_stream.str(),
198  OOMPH_CURRENT_FUNCTION,
199  OOMPH_EXCEPTION_LOCATION);
200 
201  // Return the value zero
202  return 0.0;
203  } // if (Preconditioner_has_been_setup)
204  } // End of get_memory_usage_in_bytes
205 
206  private:
207  /// Pointer to the 'preconditioner' for the F matrix
209 
210  /// Pointer to the 'preconditioner' for the pressure matrix
212 
213  /// Flag indicating whether the default F preconditioner is used
215 
216  /// Flag indicating whether the default P preconditioner is used
218 
219  /// Control flag is true if the preconditioner has been setup
220  /// (used so we can wipe the data when the preconditioner is called again)
222 
223  /// Flag to indicate whether or not to record the memory statistics
224  /// this preconditioner
226 
227  /// Storage for the memory usage of the solver if the flag above
228  /// is set to true (in bytes)
230 
231  /// MatrixVectorProduct operator for F
233 
234  /// MatrixVectorProduct operator for G
236  };
237 
238 
239  //=============================================================================
240  /// The block preconditioner form of GMRES. This version extracts
241  /// the blocks from the global systems and assembles the system by
242  /// concatenating all the matrices together
243  //=============================================================================
245  : public IterativeLinearSolver,
246  public virtual BlockPreconditioner<CRDoubleMatrix>
247  {
248  public:
249  /// Constructor (empty)
252  Matrix_pt(0),
254  Iterations(0),
256  Preconditioner_LHS(false)
257  {
258  // By default, don't store the memory statistics of this preconditioner
260 
261  // Initialise the value of Memory_usage_in_bytes
262  Memory_usage_in_bytes = 0.0;
263  } // End of GMRESBlockPreconditioner
264 
265  /// Destructor
267  {
268  // Call the auxiliary clean up function
269  this->clean_up_memory();
270  } // End of ~GMRESBlockPreconditioner
271 
272  /// Clean up the memory (empty for now...)
273  virtual void clean_up_memory()
274  {
275  // If the block preconditioner has been set up previously
277  {
278  // Delete the subsidiary preconditioner
280 
281  // Make it a null pointer
283 
284  // Delete the matrix!
285  delete Matrix_pt;
286 
287  // Make it a null pointer
288  Matrix_pt = 0;
289  }
290  } // End of clean_up_memory
291 
292  /// Broken copy constructor
294 
295  /// Broken assignment operator
296  void operator=(const GMRESBlockPreconditioner&) = delete;
297 
298  /// For some reason we need to remind the compiler that there is
299  /// also a function named setup in the base class.
300  using Preconditioner::setup;
301 
302  /// Setup the preconditioner
303  void setup();
304 
305  /// Apply preconditioner to r
307 
308  /// Solver: Takes pointer to problem and returns the results vector
309  /// which contains the solution of the linear system defined by
310  /// the problem's fully assembled Jacobian and residual vector.
311  void solve(Problem* const& problem_pt, DoubleVector& result)
312  {
313  // Broken
314  throw OomphLibError("Can't use this interface!",
315  OOMPH_CURRENT_FUNCTION,
316  OOMPH_EXCEPTION_LOCATION);
317  } // End of solve
318 
319  /// Handle to the number of iterations taken
320  unsigned iterations() const
321  {
322  // Return the number of iterations
323  return Iterations;
324  } // End of iterations
325 
326  /// Set left preconditioning (the default)
328  {
329  Preconditioner_LHS = true;
330  }
331 
332  /// Enable right preconditioning
334  {
335  Preconditioner_LHS = false;
336  }
337 
338 
339  /// Document the memory usage
341  {
342  /// Set the appropriate flag to true
344  } // End of enable_doc_memory_usage
345 
346 
347  /// Don't document the memory usage!
349  {
350  /// Set the appropriate flag to false
352  } // End of disable_doc_memory_usage
353 
354 
355  /// Get the memory statistics
357  {
358  // Has the preconditioner even been set up yet?
360  {
361  // Were we meant to compute the statistics?
363  {
364  // Return the appropriate variable value
365  return Memory_usage_in_bytes;
366  }
367  else
368  {
369  // Allocate storage for an output stream
370  std::ostringstream warning_message_stream;
371 
372  // Create a warning message
373  warning_message_stream
374  << "The memory statistics have not been calculated "
375  << "so I'm returning\nthe value zero." << std::endl;
376 
377  // Give the user a warning
378  OomphLibWarning(warning_message_stream.str(),
379  OOMPH_CURRENT_FUNCTION,
380  OOMPH_EXCEPTION_LOCATION);
381 
382  // Return the value zero
383  return 0.0;
384  }
385  }
386  // If the preconditioner hasn't been set up yet
387  else
388  {
389  // Allocate storage for an output stream
390  std::ostringstream warning_message_stream;
391 
392  // Create a warning message
393  warning_message_stream
394  << "The preconditioner hasn't even been set up yet "
395  << "so I'm returning\nthe value zero." << std::endl;
396 
397  // Give the user a warning
398  OomphLibWarning(warning_message_stream.str(),
399  OOMPH_CURRENT_FUNCTION,
400  OOMPH_EXCEPTION_LOCATION);
401 
402  // Return the value zero
403  return 0.0;
404  } // if (Preconditioner_has_been_setup)
405  } // End of get_memory_usage_in_bytes
406 
407 
408  /// Handle to the Navier-Stokes subsidiary block preconditioner
409  /// DRAIG: Make sure the desired const-ness is correct later...
411  const
412  {
413  // Return a pointer to the appropriate member data
415  } // End of navier_stokes_subsidiary_preconditioner_pt
416 
417  private:
418  /// Helper function to update the result vector using the result,
419  /// x=x_0+V_m*y
420  void update(const unsigned& k,
421  const Vector<Vector<double>>& H,
422  const Vector<double>& s,
423  const Vector<DoubleVector>& v,
424  const DoubleVector& block_x_with_size_of_full_x,
425  DoubleVector& x)
426  {
427  // Make a local copy of s
428  Vector<double> y(s);
429 
430  // Backsolve:
431  for (int i = int(k); i >= 0; i--)
432  {
433  // Divide the i-th entry of y by the i-th diagonal entry of H
434  y[i] /= H[i][i];
435 
436  // Loop over the previous values of y and update
437  for (int j = i - 1; j >= 0; j--)
438  {
439  // Update the j-th entry of y
440  y[j] -= H[i][j] * y[i];
441  }
442  } // for (int i=int(k);i>=0;i--)
443 
444  // Store the number of rows in the result vector
445  unsigned n_x = x.nrow();
446 
447  // Build a temporary vector with entries initialised to 0.0
448  DoubleVector temp(x.distribution_pt(), 0.0);
449 
450  // Build a temporary vector with entries initialised to 0.0
451  DoubleVector z(x.distribution_pt(), 0.0);
452 
453  // Get access to the underlying values
454  double* temp_pt = temp.values_pt();
455 
456  // Calculate x=Vy
457  for (unsigned j = 0; j <= k; j++)
458  {
459  // Get access to j-th column of v
460  const double* vj_pt = v[j].values_pt();
461 
462  // Loop over the entries of the vector, temp
463  for (unsigned i = 0; i < n_x; i++)
464  {
465  temp_pt[i] += vj_pt[i] * y[j];
466  }
467  } // for (unsigned j=0;j<=k;j++)
468 
469  // If we're using LHS preconditioning
470  if (Preconditioner_LHS)
471  {
472  // Since we're using LHS preconditioning the preconditioner is applied
473  // to the matrix and RHS vector so we simply update the value of x
474  x += temp;
475  }
476  // If we're using RHS preconditioning
477  else
478  {
479  // This is pretty inefficient but there is no other way to do this with
480  // block sub preconditioners as far as I can tell because they demand
481  // to have the full r and z vectors...
482  DoubleVector block_z_with_size_of_full_z(
483  block_x_with_size_of_full_x.distribution_pt());
484  DoubleVector temp_with_size_of_full_rhs(
485  block_x_with_size_of_full_x.distribution_pt());
486 
487  // Reorder the entries of temp and put them into the global-sized vector
488  this->return_block_vector(0, temp, temp_with_size_of_full_rhs);
489 
490  // Solve on the global-sized vectors
492  temp_with_size_of_full_rhs, block_z_with_size_of_full_z);
493 
494  // Now reorder the entries and put them into z
495  this->get_block_vector(0, block_z_with_size_of_full_z, z);
496 
497  // Since we're using RHS preconditioning the preconditioner is applied
498  // to the solution vector
499  // preconditioner_pt()->preconditioner_solve(temp,z);
500 
501  // Use the update: x_m=x_0+inv(M)Vy [see Saad Y,"Iterative methods for
502  // sparse linear systems", p.284]
503  x += z;
504  }
505  } // End of update
506 
507  /// Helper function: Generate a plane rotation. This is done by
508  /// finding the values of \f$ \cos(\theta) \f$ (i.e. cs) and \sin(\theta)
509  /// (i.e. sn) such that:
510  /// \f[ \begin{bmatrix} \cos\theta & \sin\theta \newline -\sin\theta & \cos\theta \end{bmatrix} \begin{bmatrix} dx \newline dy \end{bmatrix} = \begin{bmatrix} r \newline 0 \end{bmatrix}, \f]
511  /// where \f$ r=\sqrt{pow(dx,2)+pow(dy,2)} \f$. The values of a and b are
512  /// given by:
513  /// \f[ \cos\theta=\dfrac{dx}{\sqrt{pow(dx,2)+pow(dy,2)}}, \f]
514  /// and
515  /// \f[ \sin\theta=\dfrac{dy}{\sqrt{pow(dx,2)+pow(dy,2)}}. \f]
516  /// Taken from: Saad Y."Iterative methods for sparse linear systems", p.192
517  void generate_plane_rotation(double& dx, double& dy, double& cs, double& sn)
518  {
519  // If dy=0 then we do not need to apply a rotation
520  if (dy == 0.0)
521  {
522  // Using theta=0 gives cos(theta)=1
523  cs = 1.0;
524 
525  // Using theta=0 gives sin(theta)=0
526  sn = 0.0;
527  }
528  // If dx or dy is large using the normal form of calculting cs and sn
529  // is naive since this may overflow or underflow so instead we calculate
530  // r=sqrt(pow(dx,2)+pow(dy,2)) by using r=|dy|sqrt(1+pow(dx/dy,2)) if
531  // |dy|>|dx| [see <A
532  // HREF=https://en.wikipedia.org/wiki/Hypot">Hypot</A>.].
533  else if (fabs(dy) > fabs(dx))
534  {
535  // Since |dy|>|dx| calculate the ratio dx/dy
536  double temp = dx / dy;
537 
538  // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))
539  sn = 1.0 / sqrt(1.0 + temp * temp);
540 
541  // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))=(dx/dy)*sin(theta)
542  cs = temp * sn;
543  }
544  // Otherwise, we have |dx|>=|dy| so to, again, avoid overflow or underflow
545  // calculate the values of cs and sn using the method above
546  else
547  {
548  // Since |dx|>=|dy| calculate the ratio dy/dx
549  double temp = dy / dx;
550 
551  // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))
552  cs = 1.0 / sqrt(1.0 + temp * temp);
553 
554  // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))=(dy/dx)*cos(theta)
555  sn = temp * cs;
556  }
557  } // End of generate_plane_rotation
558 
559  /// Helper function: Apply plane rotation. This is done using the
560  /// update:
561  /// \f[ \begin{bmatrix} dx \newline dy \end{bmatrix} \leftarrow \begin{bmatrix} \cos\theta & \sin\theta \newline -\sin\theta & \cos\theta \end{bmatrix} \begin{bmatrix} dx \newline dy \end{bmatrix}. \f]
562  void apply_plane_rotation(double& dx, double& dy, double& cs, double& sn)
563  {
564  // Calculate the value of dx but don't update it yet
565  double temp = cs * dx + sn * dy;
566 
567  // Set the value of dy
568  dy = -sn * dx + cs * dy;
569 
570  // Set the value of dx using the correct values of dx and dy
571  dx = temp;
572  } // End of apply_plane_rotation
573 
574  /// Pointer to matrix
576 
577  /// Pointer to the preconditioner for the block matrix
580 
581  /// Number of iterations taken
582  unsigned Iterations;
583 
584  /// Flag to indicate whether or not to record the memory statistics
585  /// this preconditioner
587 
588  /// Storage for the memory usage of the solver if the flag above
589  /// is set to true (in bytes)
591 
592  /// Control flag is true if the preconditioner has been setup (used
593  /// so we can wipe the data when the preconditioner is called again)
595 
596  /// boolean indicating use of left hand preconditioning (if true)
597  /// or right hand preconditioning (if false)
599  };
600 } // End of namespace oomph
601 #endif
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
Block Preconditioner base class. The block structure of the overall problem is determined from the Me...
void return_block_vector(const unsigned &n, const DoubleVector &b, DoubleVector &v) const
Takes the n-th block ordered vector, b, and copies its entries to the appropriate entries in the natu...
void get_block_vector(const unsigned &n, const DoubleVector &v, DoubleVector &b) const
Takes the naturally ordered vector, v and returns the n-th block vector, b. Here n is the block numbe...
A class for compressed row matrices. This is a distributable object.
Definition: matrices.h:888
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
unsigned nrow() const
access function to the number of global rows.
A vector in the mathematical sense, initially developed for linear algebra type applications....
Definition: double_vector.h:58
double * values_pt()
access function to the underlying values
The block preconditioner form of GMRES. This version extracts the blocks from the global systems and ...
void operator=(const GMRESBlockPreconditioner &)=delete
Broken assignment operator.
double Memory_usage_in_bytes
Storage for the memory usage of the solver if the flag above is set to true (in bytes)
void apply_plane_rotation(double &dx, double &dy, double &cs, double &sn)
Helper function: Apply plane rotation. This is done using the update:
unsigned iterations() const
Handle to the number of iterations taken.
GMRESBlockPreconditioner(const GMRESBlockPreconditioner &)=delete
Broken copy constructor.
virtual void clean_up_memory()
Clean up the memory (empty for now...)
SpaceTimeNavierStokesSubsidiaryPreconditioner * Navier_stokes_subsidiary_preconditioner_pt
Pointer to the preconditioner for the block matrix.
bool Compute_memory_statistics
Flag to indicate whether or not to record the memory statistics this preconditioner.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
bool Preconditioner_has_been_setup
Control flag is true if the preconditioner has been setup (used so we can wipe the data when the prec...
SpaceTimeNavierStokesSubsidiaryPreconditioner * navier_stokes_subsidiary_preconditioner_pt() const
Handle to the Navier-Stokes subsidiary block preconditioner DRAIG: Make sure the desired const-ness i...
bool Preconditioner_LHS
boolean indicating use of left hand preconditioning (if true) or right hand preconditioning (if false...
void solve(Problem *const &problem_pt, DoubleVector &result)
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
void update(const unsigned &k, const Vector< Vector< double >> &H, const Vector< double > &s, const Vector< DoubleVector > &v, const DoubleVector &block_x_with_size_of_full_x, DoubleVector &x)
Helper function to update the result vector using the result, x=x_0+V_m*y.
void generate_plane_rotation(double &dx, double &dy, double &cs, double &sn)
Helper function: Generate a plane rotation. This is done by finding the values of (i....
Base class for all linear iterative solvers. This merely defines standard interfaces for linear itera...
Matrix vector product helper class - primarily a wrapper to Trilinos's Epetra matrix vector product m...
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
Preconditioner base class. Gives an interface to call all other preconditioners through and stores th...
virtual void setup()=0
Setup the preconditioner. Pure virtual generic interface function.
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition: problem.h:151
General purpose block triangular preconditioner. By default this is Upper triangular....
virtual ~SpaceTimeNavierStokesSubsidiaryPreconditioner()
Destructor - delete the preconditioner matrices.
Preconditioner * P_preconditioner_pt
Pointer to the 'preconditioner' for the pressure matrix.
double Memory_usage_in_bytes
Storage for the memory usage of the solver if the flag above is set to true (in bytes)
bool Preconditioner_has_been_setup
Control flag is true if the preconditioner has been setup (used so we can wipe the data when the prec...
bool Compute_memory_statistics
Flag to indicate whether or not to record the memory statistics this preconditioner.
void operator=(const SpaceTimeNavierStokesSubsidiaryPreconditioner &)=delete
Broken assignment operator.
SpaceTimeNavierStokesSubsidiaryPreconditioner()
Constructor. (By default this preconditioner is upper triangular).
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to r.
bool Using_default_f_preconditioner
Flag indicating whether the default F preconditioner is used.
bool Using_default_p_preconditioner
Flag indicating whether the default P preconditioner is used.
Preconditioner * F_preconditioner_pt
Pointer to the 'preconditioner' for the F matrix.
SpaceTimeNavierStokesSubsidiaryPreconditioner(const SpaceTimeNavierStokesSubsidiaryPreconditioner &)=delete
Broken copy constructor.
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition: Vector.h:58
//////////////////////////////////////////////////////////////////// ////////////////////////////////...