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-2026 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
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
44namespace oomph
45{
46 //=============================================================================
47 /// General purpose block triangular preconditioner. By default this is
48 /// Upper triangular. Also, by default ExactPreconditioner
49 /// 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 // Flag to indicate that the preconditioner has been setup
63 // previously -- if setup() is called again, data can
64 // be wiped.
66
67 // By default we use SuperLU for both p and f blocks
70
71 // Set default preconditioners (inexact solvers) -- they are
72 // members of this class!
75
76 // Null the momentum block matrix-vector product helper
77 F_mat_vec_pt = 0;
78
79 // Null the gradient block matrix-vector product helper
80 G_mat_vec_pt = 0;
81 }
82
83 /// Destructor - delete the preconditioner matrices
85 {
86 // Call the auxiliary clean up function
87 this->clean_up_memory();
88 } // End of ~SpaceTimeNavierStokesSubsidiaryPreconditioner
89
90 /// Clean up the memory
91 virtual void clean_up_memory()
92 {
93 // If we've actually set the preconditioner up
95 {
96 // Delete matvecs
97 delete F_mat_vec_pt;
98 F_mat_vec_pt = 0;
99
100 delete G_mat_vec_pt;
101 G_mat_vec_pt = 0;
102
103 // Delete the momentum block solver
104 delete F_preconditioner_pt;
106
107 // Delete the Schur complement solver
108 delete P_preconditioner_pt;
110 } // if (Preconditioner_has_been_setup)
111 } // End of clean_up_memory
112
113 /// Broken copy constructor
116
117 /// Broken assignment operator
119 delete;
120
121 /// For some reason we need to remind the compiler that there is
122 /// also a function named setup in the base class.
124
125 /// Setup the preconditioner
126 void setup();
127
128 /// Apply preconditioner to r
130
131 private:
132 /// Pointer to the 'preconditioner' for the F matrix
134
135 /// Pointer to the 'preconditioner' for the pressure matrix
137
138 /// Flag indicating whether the default F preconditioner is used
140
141 /// Flag indicating whether the default P preconditioner is used
143
144 /// Control flag is true if the preconditioner has been setup
145 /// (used so we can wipe the data when the preconditioner is called again)
147
148 /// MatrixVectorProduct operator for F
150
151 /// MatrixVectorProduct operator for G
153 };
154
155
156 //=============================================================================
157 /// The block preconditioner form of GMRES. This version extracts
158 /// the blocks from the global systems and assembles the system by
159 /// concatenating all the matrices together
160 //=============================================================================
162 : public IterativeLinearSolver,
163 public virtual BlockPreconditioner<CRDoubleMatrix>
164 {
165 public:
166 /// Constructor (empty)
176
177 /// Destructor
179 {
180 // Call the auxiliary clean up function
181 this->clean_up_memory();
182 } // End of ~GMRESBlockPreconditioner
183
184 /// Clean up the memory (empty for now...)
185 virtual void clean_up_memory()
186 {
187 // If the block preconditioner has been set up previously
189 {
190 // Delete the subsidiary preconditioner
192
193 // Make it a null pointer
195
196 // Delete the matrix!
197 delete Matrix_pt;
198
199 // Make it a null pointer
200 Matrix_pt = 0;
201 }
202 } // End of clean_up_memory
203
204 /// Broken copy constructor
206
207 /// Broken assignment operator
208 void operator=(const GMRESBlockPreconditioner&) = delete;
209
210 /// For some reason we need to remind the compiler that there is
211 /// also a function named setup in the base class.
213
214 /// Setup the preconditioner
215 void setup();
216
217 /// Apply preconditioner to r
219
220 /// Solver: Takes pointer to problem and returns the results vector
221 /// which contains the solution of the linear system defined by
222 /// the problem's fully assembled Jacobian and residual vector.
223 void solve(Problem* const& problem_pt, DoubleVector& result)
224 {
225 // Broken
226 throw OomphLibError("Can't use this interface!",
229 } // End of solve
230
231 /// Handle to the number of iterations taken
232 unsigned iterations() const
233 {
234 // Return the number of iterations
235 return Iterations;
236 } // End of iterations
237
238 /// Set left preconditioning (the default)
240 {
241 Preconditioner_LHS = true;
242 }
243
244 /// Enable right preconditioning
246 {
247 Preconditioner_LHS = false;
248 }
249
250 /// Handle to the Navier-Stokes subsidiary block preconditioner
251 /// DRAIG: Make sure the desired const-ness is correct later...
253 const
254 {
255 // Return a pointer to the appropriate member data
257 } // End of navier_stokes_subsidiary_preconditioner_pt
258
259 private:
260 /// Helper function to update the result vector using the result,
261 /// x=x_0+V_m*y
262 void update(const unsigned& k,
263 const Vector<Vector<double>>& H,
264 const Vector<double>& s,
265 const Vector<DoubleVector>& v,
267 DoubleVector& x)
268 {
269 // Make a local copy of s
270 Vector<double> y(s);
271
272 // Backsolve:
273 for (int i = int(k); i >= 0; i--)
274 {
275 // Divide the i-th entry of y by the i-th diagonal entry of H
276 y[i] /= H[i][i];
277
278 // Loop over the previous values of y and update
279 for (int j = i - 1; j >= 0; j--)
280 {
281 // Update the j-th entry of y
282 y[j] -= H[i][j] * y[i];
283 }
284 } // for (int i=int(k);i>=0;i--)
285
286 // Store the number of rows in the result vector
287 unsigned n_x = x.nrow();
288
289 // Build a temporary vector with entries initialised to 0.0
291
292 // Build a temporary vector with entries initialised to 0.0
293 DoubleVector z(x.distribution_pt(), 0.0);
294
295 // Get access to the underlying values
296 double* temp_pt = temp.values_pt();
297
298 // Calculate x=Vy
299 for (unsigned j = 0; j <= k; j++)
300 {
301 // Get access to j-th column of v
302 const double* vj_pt = v[j].values_pt();
303
304 // Loop over the entries of the vector, temp
305 for (unsigned i = 0; i < n_x; i++)
306 {
307 temp_pt[i] += vj_pt[i] * y[j];
308 }
309 } // for (unsigned j=0;j<=k;j++)
310
311 // If we're using LHS preconditioning
313 {
314 // Since we're using LHS preconditioning the preconditioner is applied
315 // to the matrix and RHS vector so we simply update the value of x
316 x += temp;
317 }
318 // If we're using RHS preconditioning
319 else
320 {
321 // This is pretty inefficient but there is no other way to do this with
322 // block sub preconditioners as far as I can tell because they demand
323 // to have the full r and z vectors...
325 block_x_with_size_of_full_x.distribution_pt());
327 block_x_with_size_of_full_x.distribution_pt());
328
329 // Reorder the entries of temp and put them into the global-sized vector
331
332 // Solve on the global-sized vectors
335
336 // Now reorder the entries and put them into z
337 this->get_block_vector(0, block_z_with_size_of_full_z, z);
338
339 // Since we're using RHS preconditioning the preconditioner is applied
340 // to the solution vector
341 // preconditioner_pt()->preconditioner_solve(temp,z);
342
343 // Use the update: x_m=x_0+inv(M)Vy [see Saad Y,"Iterative methods for
344 // sparse linear systems", p.284]
345 x += z;
346 }
347 } // End of update
348
349 /// Helper function: Generate a plane rotation. This is done by
350 /// finding the values of \f$ \cos(\theta) \f$ (i.e. cs) and \f$ \sin(\theta) \f$
351 /// (i.e. sn) such that:
352 /// \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]
353 /// where \f$ r=\sqrt{pow(dx,2)+pow(dy,2)} \f$. The values of a and b are
354 /// given by:
355 /// \f[ \cos\theta=\dfrac{dx}{\sqrt{pow(dx,2)+pow(dy,2)}}, \f]
356 /// and
357 /// \f[ \sin\theta=\dfrac{dy}{\sqrt{pow(dx,2)+pow(dy,2)}}. \f]
358 /// Taken from: Saad Y."Iterative methods for sparse linear systems", p.192
359 void generate_plane_rotation(double& dx, double& dy, double& cs, double& sn)
360 {
361 // If dy=0 then we do not need to apply a rotation
362 if (dy == 0.0)
363 {
364 // Using theta=0 gives cos(theta)=1
365 cs = 1.0;
366
367 // Using theta=0 gives sin(theta)=0
368 sn = 0.0;
369 }
370 // If dx or dy is large using the normal form of calculting cs and sn
371 // is naive since this may overflow or underflow so instead we calculate
372 // r=sqrt(pow(dx,2)+pow(dy,2)) by using r=|dy|sqrt(1+pow(dx/dy,2)) if
373 // |dy|>|dx| [see <A
374 // HREF=https://en.wikipedia.org/wiki/Hypot">Hypot</A>.].
375 else if (fabs(dy) > fabs(dx))
376 {
377 // Since |dy|>|dx| calculate the ratio dx/dy
378 double temp = dx / dy;
379
380 // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))
381 sn = 1.0 / sqrt(1.0 + temp * temp);
382
383 // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))=(dx/dy)*sin(theta)
384 cs = temp * sn;
385 }
386 // Otherwise, we have |dx|>=|dy| so to, again, avoid overflow or underflow
387 // calculate the values of cs and sn using the method above
388 else
389 {
390 // Since |dx|>=|dy| calculate the ratio dy/dx
391 double temp = dy / dx;
392
393 // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))
394 cs = 1.0 / sqrt(1.0 + temp * temp);
395
396 // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))=(dy/dx)*cos(theta)
397 sn = temp * cs;
398 }
399 } // End of generate_plane_rotation
400
401 /// Helper function: Apply plane rotation. This is done using the
402 /// update:
403 /// \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]
404 void apply_plane_rotation(double& dx, double& dy, double& cs, double& sn)
405 {
406 // Calculate the value of dx but don't update it yet
407 double temp = cs * dx + sn * dy;
408
409 // Set the value of dy
410 dy = -sn * dx + cs * dy;
411
412 // Set the value of dx using the correct values of dx and dy
413 dx = temp;
414 } // End of apply_plane_rotation
415
416 /// Pointer to matrix
418
419 /// Pointer to the preconditioner for the block matrix
422
423 /// Number of iterations taken
424 unsigned Iterations;
425
426 /// Control flag is true if the preconditioner has been setup (used
427 /// so we can wipe the data when the preconditioner is called again)
429
430 /// boolean indicating use of left hand preconditioning (if true)
431 /// or right hand preconditioning (if false)
433 };
434} // End of namespace oomph
435#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
unsigned nrow() const
access function to the number of global rows.
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
A vector in the mathematical sense, initially developed for linear algebra type applications....
The block preconditioner form of GMRES. This version extracts the blocks from the global systems and ...
void operator=(const GMRESBlockPreconditioner &)=delete
Broken assignment operator.
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.
SpaceTimeNavierStokesSubsidiaryPreconditioner * Navier_stokes_subsidiary_preconditioner_pt
Pointer to the preconditioner for the block matrix.
virtual void clean_up_memory()
Clean up the memory (empty for now...)
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....
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:154
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.
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...
void operator=(const SpaceTimeNavierStokesSubsidiaryPreconditioner &)=delete
Broken assignment operator.
SpaceTimeNavierStokesSubsidiaryPreconditioner()
Constructor. (By default this preconditioner is upper triangular).
Preconditioner * F_preconditioner_pt
Pointer to the 'preconditioner' for the F matrix.
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.
SpaceTimeNavierStokesSubsidiaryPreconditioner(const SpaceTimeNavierStokesSubsidiaryPreconditioner &)=delete
Broken copy constructor.
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition Vector.h:58
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).