oomph::AugmentedProblemGMRES Class Reference

The GMRES method. More...

#include <iterative_linear_solver.h>

+ Inheritance diagram for oomph::AugmentedProblemGMRES:

Public Member Functions

 AugmentedProblemGMRES (DoubleVector *b_pt, DoubleVector *c_pt, double *x_pt, double *rhs_pt)
 Constructor. More...
 
virtual ~AugmentedProblemGMRES ()
 Destructor: Clean up storage. More...
 
 AugmentedProblemGMRES (const AugmentedProblemGMRES &)=delete
 Broken copy constructor. More...
 
void operator= (const AugmentedProblemGMRES &)=delete
 Broken assignment operator. More...
 
void disable_resolve ()
 Overload disable resolve so that it cleans up memory too. More...
 
void solve (Problem *const &problem_pt, DoubleVector &result)
 
void solve (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
 
void solve (DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
 
void resolve (const DoubleVector &rhs, DoubleVector &result)
 
unsigned iterations () const
 Number of iterations taken. More...
 
bool iteration_restart () const
 access function indicating whether restarted GMRES is used More...
 
void enable_iteration_restart (const unsigned &restart)
 
void disable_iteration_restart ()
 Switches off iteration restart. More...
 
void set_preconditioner_LHS ()
 Set left preconditioning (the default) More...
 
void set_preconditioner_RHS ()
 Enable right preconditioning. More...
 
- Public Member Functions inherited from oomph::IterativeLinearSolver
 IterativeLinearSolver ()
 
 IterativeLinearSolver (const IterativeLinearSolver &)=delete
 Broken copy constructor. More...
 
void operator= (const IterativeLinearSolver &)=delete
 Broken assignment operator. More...
 
virtual ~IterativeLinearSolver ()
 Destructor (empty) More...
 
Preconditioner *& preconditioner_pt ()
 Access function to preconditioner. More...
 
Preconditioner *const & preconditioner_pt () const
 Access function to preconditioner (const version) More...
 
doubletolerance ()
 Access to convergence tolerance. More...
 
unsignedmax_iter ()
 Access to max. number of iterations. More...
 
void enable_doc_convergence_history ()
 Enable documentation of the convergence history. More...
 
void disable_doc_convergence_history ()
 Disable documentation of the convergence history. More...
 
void open_convergence_history_file_stream (const std::string &file_name, const std::string &zone_title="")
 
void close_convergence_history_file_stream ()
 Close convergence history output stream. More...
 
double jacobian_setup_time () const
 
double linear_solver_solution_time () const
 return the time taken to solve the linear system More...
 
virtual double preconditioner_setup_time () const
 returns the the time taken to setup the preconditioner More...
 
void enable_setup_preconditioner_before_solve ()
 Setup the preconditioner before the solve. More...
 
void disable_setup_preconditioner_before_solve ()
 Don't set up the preconditioner before the solve. More...
 
void enable_error_after_max_iter ()
 Throw an error if we don't converge within max_iter. More...
 
void disable_error_after_max_iter ()
 Don't throw an error if we don't converge within max_iter (default). More...
 
void enable_iterative_solver_as_preconditioner ()
 
void disable_iterative_solver_as_preconditioner ()
 
- Public Member Functions inherited from oomph::LinearSolver
 LinearSolver ()
 Empty constructor, initialise the member data. More...
 
 LinearSolver (const LinearSolver &dummy)=delete
 Broken copy constructor. More...
 
void operator= (const LinearSolver &)=delete
 Broken assignment operator. More...
 
virtual ~LinearSolver ()
 Empty virtual destructor. More...
 
void enable_doc_time ()
 Enable documentation of solve times. More...
 
void disable_doc_time ()
 Disable documentation of solve times. More...
 
bool is_doc_time_enabled () const
 Is documentation of solve times enabled? More...
 
bool is_resolve_enabled () const
 Boolean flag indicating if resolves are enabled. More...
 
virtual void enable_resolve ()
 
virtual void solve_transpose (Problem *const &problem_pt, DoubleVector &result)
 
virtual void solve_transpose (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &result)
 
virtual void solve_transpose (DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
 
virtual void resolve_transpose (const DoubleVector &rhs, DoubleVector &result)
 
virtual void enable_computation_of_gradient ()
 
void disable_computation_of_gradient ()
 
void reset_gradient ()
 
void get_gradient (DoubleVector &gradient)
 function to access the gradient, provided it has been computed More...
 
- Public Member Functions inherited from oomph::DistributableLinearAlgebraObject
 DistributableLinearAlgebraObject ()
 Default constructor - create a distribution. More...
 
 DistributableLinearAlgebraObject (const DistributableLinearAlgebraObject &matrix)=delete
 Broken copy constructor. More...
 
void operator= (const DistributableLinearAlgebraObject &)=delete
 Broken assignment operator. More...
 
virtual ~DistributableLinearAlgebraObject ()
 Destructor. More...
 
LinearAlgebraDistributiondistribution_pt () const
 access to the LinearAlgebraDistribution More...
 
unsigned nrow () const
 access function to the number of global rows. More...
 
unsigned nrow_local () const
 access function for the num of local rows on this processor. More...
 
unsigned nrow_local (const unsigned &p) const
 access function for the num of local rows on this processor. More...
 
unsigned first_row () const
 access function for the first row on this processor More...
 
unsigned first_row (const unsigned &p) const
 access function for the first row on this processor More...
 
bool distributed () const
 distribution is serial or distributed More...
 
bool distribution_built () const
 
void build_distribution (const LinearAlgebraDistribution *const dist_pt)
 
void build_distribution (const LinearAlgebraDistribution &dist)
 

Private Member Functions

void clean_up_memory ()
 Cleanup data that's stored for resolve (if any has been stored) More...
 
void augmented_matrix_multiply (CRDoubleMatrix *matrix_pt, const DoubleVector &x, DoubleVector &soln)
 Multiply the vector x by the augmented system matrix. More...
 
void apply_schur_complement_preconditioner (const DoubleVector &rhs, DoubleVector &soln)
 
void solve_helper (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
 General interface to solve function. More...
 
void update (const unsigned &k, const Vector< Vector< double >> &H, const Vector< double > &s, const Vector< DoubleVector > &v, DoubleVector &x)
 
void generate_plane_rotation (double &dx, double &dy, double &cs, double &sn)
 
void apply_plane_rotation (double &dx, double &dy, double &cs, double &sn)
 

Private Attributes

unsigned Iterations
 Number of iterations taken. More...
 
unsigned Restart
 
bool Iteration_restart
 boolean indicating if iteration restarting is used More...
 
CRDoubleMatrixMatrix_pt
 Pointer to matrix. More...
 
DoubleVectorB_pt
 Pointer to the column vector in the bordered system. More...
 
DoubleVectorC_pt
 Pointer to the row vector in the bordered system. More...
 
doubleX_pt
 Pointer to the last entry of the LHS vector in the bordered system. More...
 
doubleRhs_pt
 Pointer to the last entry of the RHS vector in the bordered system. More...
 
double Schur_complement_scalar
 The scalar component of the Schur complement preconditioner. More...
 
bool Resolving
 
bool Matrix_can_be_deleted
 
bool Preconditioner_LHS
 

Additional Inherited Members

- Protected Member Functions inherited from oomph::DistributableLinearAlgebraObject
void clear_distribution ()
 
- Protected Attributes inherited from oomph::IterativeLinearSolver
bool Doc_convergence_history
 
std::ofstream Output_file_stream
 Output file stream for convergence history. More...
 
double Tolerance
 Convergence tolerance. More...
 
unsigned Max_iter
 Maximum number of iterations. More...
 
PreconditionerPreconditioner_pt
 Pointer to the preconditioner. More...
 
double Jacobian_setup_time
 Jacobian setup time. More...
 
double Solution_time
 linear solver solution time More...
 
double Preconditioner_setup_time
 Preconditioner setup time. More...
 
bool Setup_preconditioner_before_solve
 
bool Throw_error_after_max_iter
 
bool Use_iterative_solver_as_preconditioner
 Use the iterative solver as preconditioner. More...
 
bool First_time_solve_when_used_as_preconditioner
 
- Protected Attributes inherited from oomph::LinearSolver
bool Enable_resolve
 
bool Doc_time
 Boolean flag that indicates whether the time taken. More...
 
bool Compute_gradient
 
bool Gradient_has_been_computed
 flag that indicates whether the gradient was computed or not More...
 
DoubleVector Gradient_for_glob_conv_newton_solve
 
- Static Protected Attributes inherited from oomph::IterativeLinearSolver
static IdentityPreconditioner Default_preconditioner
 

Detailed Description

The GMRES method.

//////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

Constructor & Destructor Documentation

◆ AugmentedProblemGMRES() [1/2]

oomph::AugmentedProblemGMRES::AugmentedProblemGMRES ( DoubleVector b_pt,
DoubleVector c_pt,
double x_pt,
double rhs_pt 
)
inline

Constructor.

1556  : Iterations(0),
1557  Matrix_pt(0),
1558  B_pt(b_pt),
1559  C_pt(c_pt),
1560  X_pt(x_pt),
1561  Rhs_pt(rhs_pt),
1563  Resolving(false),
1564  Matrix_can_be_deleted(true)
1565  {
1566  Preconditioner_LHS = true;
1567  Iteration_restart = false;
1568  }
bool Resolving
Definition: iterative_linear_solver.h:1955
DoubleVector * C_pt
Pointer to the row vector in the bordered system.
Definition: iterative_linear_solver.h:1942
CRDoubleMatrix * Matrix_pt
Pointer to matrix.
Definition: iterative_linear_solver.h:1936
bool Iteration_restart
boolean indicating if iteration restarting is used
Definition: iterative_linear_solver.h:1933
double * Rhs_pt
Pointer to the last entry of the RHS vector in the bordered system.
Definition: iterative_linear_solver.h:1948
double Schur_complement_scalar
The scalar component of the Schur complement preconditioner.
Definition: iterative_linear_solver.h:1951
double * X_pt
Pointer to the last entry of the LHS vector in the bordered system.
Definition: iterative_linear_solver.h:1945
unsigned Iterations
Number of iterations taken.
Definition: iterative_linear_solver.h:1926
bool Matrix_can_be_deleted
Definition: iterative_linear_solver.h:1959
DoubleVector * B_pt
Pointer to the column vector in the bordered system.
Definition: iterative_linear_solver.h:1939
bool Preconditioner_LHS
Definition: iterative_linear_solver.h:1963

References Iteration_restart, and Preconditioner_LHS.

◆ ~AugmentedProblemGMRES()

virtual oomph::AugmentedProblemGMRES::~AugmentedProblemGMRES ( )
inlinevirtual

Destructor: Clean up storage.

1572  {
1573  clean_up_memory();
1574  }
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
Definition: iterative_linear_solver.h:1687

References clean_up_memory().

◆ AugmentedProblemGMRES() [2/2]

oomph::AugmentedProblemGMRES::AugmentedProblemGMRES ( const AugmentedProblemGMRES )
delete

Broken copy constructor.

Member Function Documentation

◆ apply_plane_rotation()

void oomph::AugmentedProblemGMRES::apply_plane_rotation ( double dx,
double dy,
double cs,
double sn 
)
inlineprivate

Helper function: Apply plane rotation. This is done using the update:

\[ \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}. \]

1914  {
1915  // Calculate the value of dx but don't update it yet
1916  double temp = cs * dx + sn * dy;
1917 
1918  // Set the value of dy
1919  dy = -sn * dx + cs * dy;
1920 
1921  // Set the value of dx using the correct values of dx and dy
1922  dx = temp;
1923  }

Referenced by solve_helper().

◆ apply_schur_complement_preconditioner()

void oomph::AugmentedProblemGMRES::apply_schur_complement_preconditioner ( const DoubleVector rhs,
DoubleVector soln 
)
inlineprivate

Apply the block-diagonal Schur complement preconditioner to compute the LHS which has size N+1 (the augmented system size)

1738  {
1739  // How many dofs are there in the non-augmented system?
1740  unsigned n_dof = this->distribution_pt()->nrow();
1741 
1742  // Compute the final entry of r first
1743  soln[n_dof] = rhs[n_dof] / Schur_complement_scalar;
1744 
1745  // Do we want to use a block-diagonal approximation? The default is to
1746  // use a block upper-triangular approximation for the preconditioner
1747  bool use_block_diagonal_preconditioner = false;
1748 
1749  // Allocate space for (the non-augmented part of) r satisfying b-Jx = Mr
1750  DoubleVector r_small(this->distribution_pt(), 0.0);
1751 
1752  // Allocate space for the non-augmented system part of the RHS vector
1753  DoubleVector rhs_small(this->distribution_pt(), 0.0);
1754 
1755  // Loop over the first n_dof entries of the RHS vector
1756  for (unsigned i = 0; i < n_dof; i++)
1757  {
1758  // If we want to use the block-diagonal preconditioner
1759  if (use_block_diagonal_preconditioner)
1760  {
1761  // Copy the i-th entry over
1762  rhs_small[i] = rhs[i];
1763  }
1764  // If we want to use the block upper-triangular preconditioner
1765  else
1766  {
1767  // Copy the i-th entry over
1768  rhs_small[i] = rhs[i] - soln[n_dof] * (*B_pt)[i];
1769  }
1770  } // for (unsigned i=0;i<n_dof;i++)
1771 
1772  // Apply the preconditioner
1773  preconditioner_pt()->preconditioner_solve(rhs_small, r_small);
1774 
1775  // Loop over the first n_dof entries of the solution vector
1776  for (unsigned i = 0; i < n_dof; i++)
1777  {
1778  // Copy the i-th entry over
1779  soln[i] = r_small[i];
1780  }
1781  } // End of apply_schur_complement_preconditioner
int i
Definition: BiCGSTAB_step_by_step.cpp:9
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
Definition: linear_algebra_distribution.h:457
Preconditioner *& preconditioner_pt()
Access function to preconditioner.
Definition: iterative_linear_solver.h:95
unsigned nrow() const
access function to the number of global rows.
Definition: linear_algebra_distribution.h:186
virtual void preconditioner_solve(const DoubleVector &r, DoubleVector &z)=0

References oomph::DistributableLinearAlgebraObject::distribution_pt(), i, oomph::LinearAlgebraDistribution::nrow(), oomph::IterativeLinearSolver::preconditioner_pt(), oomph::Preconditioner::preconditioner_solve(), and Schur_complement_scalar.

Referenced by solve_helper(), and update().

◆ augmented_matrix_multiply()

void oomph::AugmentedProblemGMRES::augmented_matrix_multiply ( CRDoubleMatrix matrix_pt,
const DoubleVector x,
DoubleVector soln 
)
inlineprivate

Multiply the vector x by the augmented system matrix.

1700  {
1701  // How many dofs are there in the non-augmented system?
1702  unsigned n_dof = matrix_pt->nrow();
1703 
1704  // Allocate space for the non-augmented component of x
1705  DoubleVector x_small(this->distribution_pt(), 0.0);
1706 
1707  // Loop over the first n_dof entries of x
1708  for (unsigned i = 0; i < n_dof; i++)
1709  {
1710  // Copy the i-th entry over
1711  x_small[i] = x[i];
1712  }
1713 
1714  // Allocate space for the product of the matrix and x_small
1715  DoubleVector a_prod_xsmall(this->distribution_pt(), 0.0);
1716 
1717  // Now multiply the matrix and x_small
1718  matrix_pt->multiply(x_small, a_prod_xsmall);
1719 
1720  // Get the scalar component of x associated with the system augmentation
1721  double y = x[n_dof];
1722 
1723  // Loop over the first n_dof entries of soln
1724  for (unsigned i = 0; i < n_dof; i++)
1725  {
1726  // Compute the i-th entry
1727  soln[i] = a_prod_xsmall[i] + y * (*B_pt)[i];
1728  }
1729 
1730  // Compute the final entry of soln
1731  soln[n_dof] = C_pt->dot(x_small);
1732  } // End of augmented_matrix_multiply
double dot(const DoubleVector &vec) const
compute the dot product of this vector with the vector vec.
Definition: double_vector.cc:805
Scalar * y
Definition: level1_cplx_impl.h:128
list x
Definition: plotDoE.py:28

References C_pt, oomph::DistributableLinearAlgebraObject::distribution_pt(), oomph::DoubleVector::dot(), i, oomph::CRDoubleMatrix::multiply(), oomph::CRDoubleMatrix::nrow(), plotDoE::x, and y.

Referenced by solve_helper().

◆ clean_up_memory()

void oomph::AugmentedProblemGMRES::clean_up_memory ( )
inlineprivatevirtual

Cleanup data that's stored for resolve (if any has been stored)

Reimplemented from oomph::LinearSolver.

1688  {
1689  if ((Matrix_pt != 0) && (Matrix_can_be_deleted))
1690  {
1691  delete Matrix_pt;
1692  Matrix_pt = 0;
1693  }
1694  } // End of clean_up_memory

References Matrix_can_be_deleted, and Matrix_pt.

Referenced by disable_resolve(), solve(), and ~AugmentedProblemGMRES().

◆ disable_iteration_restart()

void oomph::AugmentedProblemGMRES::disable_iteration_restart ( )
inline

Switches off iteration restart.

1669  {
1670  Iteration_restart = false;
1671  } // End of disable_iteration_restart

References Iteration_restart.

◆ disable_resolve()

void oomph::AugmentedProblemGMRES::disable_resolve ( )
inlinevirtual

Overload disable resolve so that it cleans up memory too.

Reimplemented from oomph::LinearSolver.

1584  {
1586  clean_up_memory();
1587  } // End of disable_resolve
virtual void disable_resolve()
Definition: linear_solver.h:144

References clean_up_memory(), and oomph::LinearSolver::disable_resolve().

◆ enable_iteration_restart()

void oomph::AugmentedProblemGMRES::enable_iteration_restart ( const unsigned restart)
inline

switches on iteration restarting and takes as an argument the number of iterations after which the construction of the orthogonalisation basis vectors should be restarted

1662  {
1663  Restart = restart;
1664  Iteration_restart = true;
1665  }
Definition: flowRule_restart.cpp:8
Definition: restart2.cpp:8

References Iteration_restart.

◆ generate_plane_rotation()

void oomph::AugmentedProblemGMRES::generate_plane_rotation ( double dx,
double dy,
double cs,
double sn 
)
inlineprivate

Helper function: Generate a plane rotation. This is done by finding the values of \( \cos(\theta) \) (i.e. cs) and \sin(\theta) (i.e. sn) such that:

\[ \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}, \]

where \( r=\sqrt{pow(dx,2)+pow(dy,2)} \). The values of a and b are given by:

\[ \cos\theta&=\dfrac{dx}{\sqrt{pow(dx,2)+pow(dy,2)}}, \]

and

\[ \sin\theta&=\dfrac{dy}{\sqrt{pow(dx,2)+pow(dy,2)}}. \]

Taken from: Saad Y."Iterative methods for sparse linear systems", p.192

1869  {
1870  // If dy=0 then we do not need to apply a rotation
1871  if (dy == 0.0)
1872  {
1873  // Using theta=0 gives cos(theta)=1
1874  cs = 1.0;
1875 
1876  // Using theta=0 gives sin(theta)=0
1877  sn = 0.0;
1878  }
1879  // If dx or dy is large using the normal form of calculting cs and sn
1880  // is naive since this may overflow or underflow so instead we calculate
1881  // r=sqrt(pow(dx,2)+pow(dy,2)) by using r=|dy|sqrt(1+pow(dx/dy,2)) if
1882  // |dy|>|dx| [see <A
1883  // HREF=https://en.wikipedia.org/wiki/Hypot">Hypot</A>.].
1884  else if (fabs(dy) > fabs(dx))
1885  {
1886  // Since |dy|>|dx| calculate the ratio dx/dy
1887  double temp = dx / dy;
1888 
1889  // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))
1890  sn = 1.0 / sqrt(1.0 + temp * temp);
1891 
1892  // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))=(dx/dy)*sin(theta)
1893  cs = temp * sn;
1894  }
1895  // Otherwise, we have |dx|>=|dy| so to, again, avoid overflow or underflow
1896  // calculate the values of cs and sn using the method above
1897  else
1898  {
1899  // Since |dx|>=|dy| calculate the ratio dy/dx
1900  double temp = dy / dx;
1901 
1902  // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))
1903  cs = 1.0 / sqrt(1.0 + temp * temp);
1904 
1905  // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))=(dy/dx)*cos(theta)
1906  sn = temp * cs;
1907  }
1908  } // End of generate_plane_rotation
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:117

References boost::multiprecision::fabs(), and sqrt().

Referenced by solve_helper().

◆ iteration_restart()

bool oomph::AugmentedProblemGMRES::iteration_restart ( ) const
inline

access function indicating whether restarted GMRES is used

1654  {
1655  return Iteration_restart;
1656  }

References Iteration_restart.

◆ iterations()

unsigned oomph::AugmentedProblemGMRES::iterations ( ) const
inlinevirtual

Number of iterations taken.

Implements oomph::IterativeLinearSolver.

1648  {
1649  return Iterations;
1650  }

References Iterations.

◆ operator=()

void oomph::AugmentedProblemGMRES::operator= ( const AugmentedProblemGMRES )
delete

Broken assignment operator.

◆ resolve()

void oomph::AugmentedProblemGMRES::resolve ( const DoubleVector rhs,
DoubleVector result 
)
virtual

Re-solve the system defined by the last assembled Jacobian and the rhs vector specified here. Solution is returned in the vector result.

\Short Re-solve the system defined by the last assembled Jacobian and the rhs vector specified here. Solution is returned in the vector result.

Reimplemented from oomph::LinearSolver.

2833  {
2834  // We are re-solving
2835  Resolving = true;
2836 
2837 #ifdef PARANOID
2838  if (Matrix_pt == 0)
2839  {
2840  throw OomphLibError("No matrix was stored -- cannot re-solve",
2843  }
2844 #endif
2845 
2846  // Call linear algebra-style solver
2847  this->solve(Matrix_pt, rhs, result);
2848 
2849  // Reset re-solving flag
2850  Resolving = false;
2851  }
void solve(Problem *const &problem_pt, DoubleVector &result)
Definition: iterative_linear_solver.cc:2746
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References Matrix_pt, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Resolving, and solve().

◆ set_preconditioner_LHS()

void oomph::AugmentedProblemGMRES::set_preconditioner_LHS ( )
inline

Set left preconditioning (the default)

1675  {
1676  Preconditioner_LHS = true;
1677  }

References Preconditioner_LHS.

◆ set_preconditioner_RHS()

void oomph::AugmentedProblemGMRES::set_preconditioner_RHS ( )
inline

Enable right preconditioning.

1681  {
1682  Preconditioner_LHS = false;
1683  }

References Preconditioner_LHS.

◆ solve() [1/3]

void oomph::AugmentedProblemGMRES::solve ( DoubleMatrixBase *const &  matrix_pt,
const DoubleVector rhs,
DoubleVector solution 
)
inlinevirtual

Linear-algebra-type solver: Takes pointer to a matrix and rhs vector and returns the solution of the linear system.

Reimplemented from oomph::LinearSolver.

1599  {
1600  // Upcast to a CRDoubleMatrix
1601  CRDoubleMatrix* cr_matrix_pt = dynamic_cast<CRDoubleMatrix*>(matrix_pt);
1602 
1603  // If we can't upcast to a CRDoubleMatrix then this won't work...
1604  if (cr_matrix_pt == 0)
1605  {
1606  // Throw an error
1607  throw OomphLibError("Can't upcast input matrix to a CRDoubleMatrix!",
1610  }
1611 
1612  // Set up the distribution
1613  this->build_distribution(cr_matrix_pt->distribution_pt());
1614 
1615  // Store the matrix if required
1616  if ((Enable_resolve) && (!Resolving))
1617  {
1618  // Store a pointer to the upcasted matrix
1619  Matrix_pt = cr_matrix_pt;
1620 
1621  // Matrix has been passed in from the outside so we must not
1622  // delete it
1623  Matrix_can_be_deleted = false;
1624  }
1625 
1626  // Call the helper function
1627  this->solve_helper(matrix_pt, rhs, solution);
1628  } // End of solve
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
Definition: iterative_linear_solver.cc:2862
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
Definition: linear_algebra_distribution.h:507
bool Enable_resolve
Definition: linear_solver.h:73
void solution(const Vector< double > &x, Vector< double > &u)
Definition: two_d_biharmonic.cc:113

References oomph::DistributableLinearAlgebraObject::build_distribution(), oomph::DistributableLinearAlgebraObject::distribution_pt(), oomph::LinearSolver::Enable_resolve, Matrix_can_be_deleted, Matrix_pt, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Resolving, BiharmonicTestFunctions1::solution(), and solve_helper().

◆ solve() [2/3]

void oomph::AugmentedProblemGMRES::solve ( DoubleMatrixBase *const &  matrix_pt,
const Vector< double > &  rhs,
Vector< double > &  result 
)
inlinevirtual

Linear-algebra-type solver: Takes pointer to a matrix and rhs vector and returns the solution of the linear system Call the broken base-class version. If you want this, please implement it

Reimplemented from oomph::LinearSolver.

1637  {
1638  LinearSolver::solve(matrix_pt, rhs, result);
1639  }
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0

References oomph::LinearSolver::solve().

◆ solve() [3/3]

void oomph::AugmentedProblemGMRES::solve ( Problem *const &  problem_pt,
DoubleVector result 
)
virtual

Solver: Takes pointer to problem and returns the results vector which contains the solution of the linear system defined by the problem's fully assembled Jacobian and residual vector.

//////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// Solver: Takes pointer to problem and returns the results vector which contains the solution of the linear system defined by the problem's fully assembled Jacobian and residual vector.

Implements oomph::LinearSolver.

2748  {
2749  // Find # of degrees of freedom (in the non-augmented problem)
2750  unsigned n_dof = problem_pt->ndof();
2751 
2752  // Initialise timer
2753  double t_start = TimingHelpers::timer();
2754 
2755  // We're not re-solving
2756  Resolving = false;
2757 
2758  // Get rid of any previously stored data
2759  clean_up_memory();
2760 
2761  // Create a distribution
2762  LinearAlgebraDistribution dist(problem_pt->communicator_pt(), n_dof, false);
2763 
2764  // ...now build it
2765  this->build_distribution(dist);
2766 
2767  // Get the Jacobian matrix and the nonlinear residual vector
2768  Matrix_pt = new CRDoubleMatrix;
2769  DoubleVector f;
2770  if (dynamic_cast<DistributableLinearAlgebraObject*>(Matrix_pt) != 0)
2771  {
2772  if (dynamic_cast<CRDoubleMatrix*>(Matrix_pt) != 0)
2773  {
2774  dynamic_cast<CRDoubleMatrix*>(Matrix_pt)->build(
2775  this->distribution_pt());
2776  f.build(this->distribution_pt(), 0.0);
2777  }
2778  }
2779  problem_pt->get_jacobian(f, *Matrix_pt);
2780 
2781  // We've made the matrix, we can delete it...
2782  Matrix_can_be_deleted = true;
2783 
2784  // Doc time for setup
2785  double t_end = TimingHelpers::timer();
2786  Jacobian_setup_time = t_end - t_start;
2787 
2788  if (Doc_time)
2789  {
2790  oomph_info << "Time for setup of Jacobian [sec]: " << Jacobian_setup_time
2791  << std::endl;
2792  }
2793 
2794  // Reset the Schur complement scalar entry value
2796 
2797  // Call linear algebra-style solver. If the result distribution is wrong,
2798  // then redistribute before the solve and return to original distribution
2799  // afterwards
2800  if ((!(*result.distribution_pt() == *this->distribution_pt())) &&
2801  result.built())
2802  {
2803  // Create a temporary copy of the current result distribution
2804  LinearAlgebraDistribution temp_global_dist(result.distribution_pt());
2805 
2806  // Re-build the result vector as an augmented vector
2807  result.build(dist, 0.0);
2808 
2809  // Call the auxilliary helper function to do the actual solve
2810  this->solve_helper(Matrix_pt, f, result);
2811 
2812  // Re-distribute result vector
2813  result.redistribute(&temp_global_dist);
2814  }
2815  // Otherwise just solve
2816  else
2817  {
2818  // Call the auxilliary helper function to do the actual solve
2819  this->solve_helper(Matrix_pt, f, result);
2820  }
2821 
2822  // Kill matrix unless it's still required for resolve
2824  };
DistributableLinearAlgebraObject()
Default constructor - create a distribution.
Definition: linear_algebra_distribution.h:438
double Jacobian_setup_time
Jacobian setup time.
Definition: iterative_linear_solver.h:248
bool Doc_time
Boolean flag that indicates whether the time taken.
Definition: linear_solver.h:77
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
double timer()
returns the time in seconds after some point in past
Definition: oomph_utilities.cc:1295
OomphInfo oomph_info
Definition: oomph_definitions.cc:319

References oomph::DoubleVector::build(), oomph::DistributableLinearAlgebraObject::build_distribution(), oomph::DoubleVector::built(), clean_up_memory(), oomph::Problem::communicator_pt(), oomph::DistributableLinearAlgebraObject::distribution_pt(), oomph::LinearSolver::Doc_time, oomph::LinearSolver::Enable_resolve, f(), oomph::Problem::get_jacobian(), oomph::IterativeLinearSolver::Jacobian_setup_time, Matrix_can_be_deleted, Matrix_pt, oomph::Problem::ndof(), oomph::oomph_info, oomph::DoubleVector::redistribute(), Resolving, Schur_complement_scalar, solve_helper(), and oomph::TimingHelpers::timer().

Referenced by resolve().

◆ solve_helper()

void oomph::AugmentedProblemGMRES::solve_helper ( DoubleMatrixBase *const &  input_matrix_pt,
const DoubleVector rhs,
DoubleVector lhs 
)
private

General interface to solve function.

Linear-algebra-type solver: Takes pointer to a matrix and rhs vector and returns the solution of the linear system. based on the algorithm presented in Templates for the Solution of Linear Systems: Building Blocks for Iterative Methods, Barrett, Berry et al, SIAM, 2006 and the implementation in the IML++ library : http://math.nist.gov/iml++/

2866  {
2867  // Get number of dofs (in the non-augmented problem)
2868  unsigned n_dof = input_matrix_pt->nrow();
2869 
2870  // How many dofs in the augmented problem?
2871  unsigned n_aug_dof = n_dof + 1;
2872 
2873  // Get a handle to this Problems communicator
2874  OomphCommunicator* comm_pt = this->distribution_pt()->communicator_pt();
2875 
2876  // Set up the (non-augmented) distribution
2877  LinearAlgebraDistribution dist(comm_pt, n_dof, false);
2878 
2879  // Set up the (augmented) distribution
2880  LinearAlgebraDistribution aug_dist(comm_pt, n_aug_dof, false);
2881 
2882  // If the input vector doesn't have size N+1 then something has gone wrong
2883  if ((rhs.nrow() != n_dof) || (lhs.nrow() != n_dof))
2884  {
2885  // Create an output stream
2886  std::ostringstream error_message_stream;
2887 
2888  // Create the error message
2889  error_message_stream << "RHS vector has " << rhs.nrow()
2890  << " rows and the "
2891  << "LHS vector has " << rhs.nrow()
2892  << " rows but\nthey "
2893  << "should both have " << n_dof << " rows!"
2894  << std::endl;
2895 
2896  // Throw an error
2897  throw OomphLibError(error_message_stream.str(),
2900  }
2901 
2902 #ifdef PARANOID
2903  // PARANOID check that if the matrix is distributable then it should not be
2904  // then it should not be distributed
2905  if (dynamic_cast<DistributableLinearAlgebraObject*>(input_matrix_pt) != 0)
2906  {
2907  if (dynamic_cast<DistributableLinearAlgebraObject*>(input_matrix_pt)
2908  ->distributed())
2909  {
2910  std::ostringstream error_message_stream;
2911  error_message_stream << "The matrix must not be distributed.";
2912  throw OomphLibError(error_message_stream.str(),
2915  }
2916  }
2917  // PARANOID check that this rhs distribution is setup
2918  if (!rhs.built())
2919  {
2920  std::ostringstream error_message_stream;
2921  error_message_stream << "The rhs vector distribution must be setup.";
2922  throw OomphLibError(error_message_stream.str(),
2925  }
2926  // PARANOID check that the rhs is not distributed
2927  if (rhs.distribution_pt()->distributed())
2928  {
2929  std::ostringstream error_message_stream;
2930  error_message_stream << "The rhs vector must not be distributed.";
2931  throw OomphLibError(error_message_stream.str(),
2934  }
2935  // PARANOID check that if the result is setup it matches the distribution
2936  // of the rhs
2937  if (lhs.built())
2938  {
2939  if (!(*rhs.distribution_pt() == *lhs.distribution_pt()))
2940  {
2941  std::ostringstream error_message_stream;
2942  error_message_stream << "If the result distribution is setup then it "
2943  "must be the same as the "
2944  << "rhs distribution";
2945  throw OomphLibError(error_message_stream.str(),
2948  }
2949  }
2950 #endif
2951 
2952  // Set up the solution if it is not
2953  if (!lhs.built())
2954  {
2955  // Use the augmented distribution which has size N+1 (not the solvers
2956  // distribution which has size N)
2957  lhs.build(dist, 0.0);
2958  }
2959  // Otherwise initialise to zero
2960  else
2961  {
2962  lhs.initialise(0.0);
2963  }
2964 
2965  // Create a vector to store the augmented LHS vector entries
2966  DoubleVector solution(aug_dist, 0.0);
2967 
2968  // Time solver
2969  double t_start = TimingHelpers::timer();
2970 
2971  // Relative residual
2972  double resid;
2973 
2974  // Iteration counter
2975  unsigned iter = 1;
2976 
2977  // if not using iteration restart set Restart to n_aug_dof
2978  if (!Iteration_restart)
2979  {
2980  Restart = n_aug_dof;
2981  }
2982 
2983  // initialise vectors
2984  Vector<double> s(Restart + 1, 0);
2985  Vector<double> cs(Restart + 1);
2986  Vector<double> sn(Restart + 1);
2987  DoubleVector w(aug_dist, 0.0);
2988 
2989  // Set up the preconditioner only if we're not re-solving
2990  if (!Resolving)
2991  {
2992  // Only setup the preconditioner before solve if require
2994  {
2995  // Setup preconditioner from the Jacobian matrix
2996  double t_start_prec = TimingHelpers::timer();
2997 
2998  // Do not setup
2999  preconditioner_pt()->setup(input_matrix_pt);
3000 
3001  // Doc time for setup of preconditioner
3002  double t_end_prec = TimingHelpers::timer();
3003  Preconditioner_setup_time = t_end_prec - t_start_prec;
3004 
3005  // If we're meant to document timings
3006  if (Doc_time)
3007  {
3008  oomph_info << "Time for setup of preconditioner [sec]: "
3009  << Preconditioner_setup_time << std::endl;
3010  }
3011  } // if (Setup_preconditioner_before_solve)
3012  }
3013  else
3014  {
3015  // If we're meant to document timings
3016  if (Doc_time)
3017  {
3018  oomph_info << "Setup of preconditioner is bypassed in resolve mode"
3019  << std::endl;
3020  }
3021  } // if (!Resolving)
3022 
3023  // The default system matrix is simply the one that was passed in
3024  CRDoubleMatrix* matrix_pt = dynamic_cast<CRDoubleMatrix*>(input_matrix_pt);
3025 
3026  // Storage for the time taken for all preconditioner applications
3027  double t_prec_application_total = 0.0;
3028 
3029  //---------------------------------------------------------------
3030  // Compute the scalar component of the diagonal Schur complement
3031  // preconditioner. NOTE: Only compute it if it is currently set
3032  // to the default value of unity. It's quite unlikely that it
3033  // will actually have value one (up to machine precision) in
3034  // practice. This check ensures that we only compute the value
3035  // during the solve function and not during the resolve.
3036  //---------------------------------------------------------------
3037  // If the Schur complement value has its default value of one
3038  if (std::fabs(Schur_complement_scalar - 1.0) < 1.0e-14)
3039  {
3040  // If the bordering vectors haven't actually been properly created
3041  if ((B_pt == 0) || (C_pt == 0))
3042  {
3043  // Throw an error
3044  throw OomphLibError("Bordering vectors have not been created!",
3047  }
3048  // Make sure the bordering vectors have the right size
3049  else if ((B_pt->nrow() != n_dof) || (C_pt->nrow() != n_dof))
3050  {
3051  // Throw an error
3052  throw OomphLibError("Bordering vectors do not have the right size!",
3055  }
3056 
3057  // Allocate storage for A^{-1}b
3058  DoubleVector a_inv_b(this->distribution_pt(), 0.0);
3059 
3060  // Compute A^{-1}b with the preconditioner approximation to A^{-1}
3062 
3063  // Now compute the scalar component of the Schur complement preconditioner
3064  Schur_complement_scalar = C_pt->dot(a_inv_b);
3065 
3066  // If the Schur complement scalar value is pratically zero or is NaN
3067  if ((std::fabs(Schur_complement_scalar) < 1.0e-14) ||
3069  {
3070  // Reset it to have value 2.0 (not 1.0 otherwise we would end up
3071  // recomputing it every resolve) as we "should" be able to use
3072  // any scalar value and end up with the same number of distinct
3073  // eigenvalues for the preconditioned system).
3075  }
3076  } // if (std::fabs(Schur_complement_scalar-1.0)<1.0e-14)
3077 
3078  // Storage for the augmented RHS vector
3079  DoubleVector rhs_aug(aug_dist, 0.0);
3080 
3081  // Loop over the first n_dof entries of the RHS vector
3082  for (unsigned i = 0; i < n_dof; i++)
3083  {
3084  // Copy the i-th entry over
3085  rhs_aug[i] = rhs[i];
3086  }
3087 
3088  // Update the RHS entry associated with the augmented equation
3089  rhs_aug[n_dof] = (*Rhs_pt);
3090 
3091  // Storage for b-Jx=Mr for r (assumes x = 0);
3092  DoubleVector r(aug_dist, 0.0);
3093 
3094  // If we're using LHS preconditioning
3095  if (Preconditioner_LHS)
3096  {
3097  // Initialise timer
3098  double t_prec_application_start = TimingHelpers::timer();
3099 
3100  // Use the helper function to apply the Schur complement preconditioner
3102 
3103  // Doc time for setup of preconditioner
3104  double t_prec_application_end = TimingHelpers::timer();
3105 
3106  // Update the preconditioner application time total
3107  t_prec_application_total +=
3108  (t_prec_application_end - t_prec_application_start);
3109  }
3110  // If we're using RHS preconditioning
3111  else
3112  {
3113  // We don't need to do any preconditioning here; just copy the vector over
3114  r = rhs_aug;
3115  } // if (Preconditioner_LHS)
3116 
3117  // Compute the norm of the RHS vector
3118  double normb = r.norm();
3119 
3120  // Set beta (the initial residual)
3121  double beta = normb;
3122 
3123  // If the RHS vector is (numerically equivalent to) the zero vector
3124  if (normb == 0.0)
3125  {
3126  // Initialise the norm of b as unity
3127  normb = 1.0;
3128  }
3129 
3130  // Compute the relative residual
3131  resid = beta / normb;
3132 
3133  // If required will document convergence history to screen or file (if
3134  // stream open)
3136  {
3137  if (!Output_file_stream.is_open())
3138  {
3139  oomph_info << 0 << " " << resid << std::endl;
3140  }
3141  else
3142  {
3143  Output_file_stream << 0 << " " << resid << std::endl;
3144  }
3145  } // if (Doc_convergence_history)
3146 
3147  // If GMRES converges immediately
3148  if (resid <= Tolerance)
3149  {
3150  if (Doc_time)
3151  {
3152  oomph_info << "AugmentedProblemGMRES converged immediately. Normalised "
3153  << "residual norm: " << resid << std::endl;
3154  }
3155 
3156  // Doc time for solver
3157  double t_end = TimingHelpers::timer();
3158  Solution_time = t_end - t_start;
3159 
3160  if (Doc_time)
3161  {
3162  oomph_info
3163  << "Time for all preconditioner applications [sec]: "
3164  << t_prec_application_total
3165  << "\nTotal time for solve with AugmentedProblemGMRES [sec]: "
3166  << Solution_time << std::endl;
3167  }
3168 
3169  // We're done so finish here
3170  return;
3171  }
3172 
3173  // initialise vector of orthogonal basis vectors (v) and upper hessenberg
3174  // matrix H
3175  // NOTE: for implementation purpose the upper hessenberg matrix indexes are
3176  // are swapped so the matrix is effectively transposed
3177  Vector<DoubleVector> v;
3178  v.resize(Restart + 1);
3179  Vector<Vector<double>> H(Restart + 1);
3180 
3181  // while...
3182  while (iter <= Max_iter)
3183  {
3184  // Copy the values of r into the zeroth basis vector v[0]
3185  v[0] = r;
3186 
3187  // Now scale it so the zeroth basis vector v[0] is r/beta
3188  v[0] /= beta;
3189 
3190  // Set the first entry of s
3191  s[0] = beta;
3192 
3193  // Counter for the inner iteration counter (restarted version)
3194  unsigned iter_restart = 0;
3195 
3196  // Start performing iterations
3197  for (iter_restart = 0; iter_restart < Restart && iter <= Max_iter;
3198  iter_restart++, iter++)
3199  {
3200  // Resize next column of upper hessenberg matrix
3201  H[iter_restart].resize(iter_restart + 2);
3202 
3203  // solve Jv[i] = Mw for w
3204  {
3205  // Allocate space for the product J*v[i]
3206  DoubleVector temp(aug_dist, 0.0);
3207 
3208  // If we're using LHS preconditioning
3209  if (Preconditioner_LHS)
3210  {
3211  // Compute J*v[i] where J is now the augmented system matrix
3212  augmented_matrix_multiply(matrix_pt, v[iter_restart], temp);
3213 
3214  // Initialise timer
3215  double t_prec_application_start = TimingHelpers::timer();
3216 
3217  // Use the helper function to apply the Schur complement
3218  // preconditioner
3220 
3221  // End timer
3222  double t_prec_application_end = TimingHelpers::timer();
3223 
3224  // Update the preconditioner application time total
3225  t_prec_application_total +=
3226  (t_prec_application_end - t_prec_application_start);
3227  }
3228  else
3229  {
3230  // Initialise timer
3231  double t_prec_application_start = TimingHelpers::timer();
3232 
3233  // Compute w=JM^{-1}v by saad p270
3234  apply_schur_complement_preconditioner(v[iter_restart], temp);
3235 
3236  // Doc time for setup of preconditioner
3237  double t_prec_application_end = TimingHelpers::timer();
3238 
3239  // Update the preconditioner application time total
3240  t_prec_application_total +=
3241  (t_prec_application_end - t_prec_application_start);
3242 
3243  // Calculate w=Jv_m where v_m=M^{-1}v
3244  augmented_matrix_multiply(matrix_pt, temp, w);
3245  }
3246  } // Solve Jv[i]=Mw for w
3247 
3248  // Get a pointer to the entries of w
3249  double* w_pt = w.values_pt();
3250 
3251  // Loop over the rows of the Hessenberg matrix
3252  for (unsigned k = 0; k <= iter_restart; k++)
3253  {
3254  // Compute the (k,iter_restart)-th entry of the Hessenberg matrix
3255  // (which is stored in its transposed form)
3256  H[iter_restart][k] = w.dot(v[k]);
3257 
3258  // Get a pointer to the entries of the k-th basis vector
3259  double* vk_pt = v[k].values_pt();
3260 
3261  // Loop over the entries of w
3262  for (unsigned i = 0; i < n_aug_dof; i++)
3263  {
3264  // Update the i-th entry of w
3265  w_pt[i] -= H[iter_restart][k] * vk_pt[i];
3266  }
3267  } // for (unsigned k=0;k<=iter_restart;k++)
3268 
3269  // Calculate the subdiagonal Hessenberg entry
3270  H[iter_restart][iter_restart + 1] = w.norm();
3271 
3272  // Copy the entries of w into the next basis vector
3273  v[iter_restart + 1] = w;
3274 
3275  // Now normalise the basis vector with the appropriate Hessenberg entry
3276  v[iter_restart + 1] /= H[iter_restart][iter_restart + 1];
3277 
3278  // Loop over the rows of the Hessenberg matrix
3279  for (unsigned k = 0; k < iter_restart; k++)
3280  {
3281  // Apply a Givens rotation to the appropriate entries of H
3283  H[iter_restart][k], H[iter_restart][k + 1], cs[k], sn[k]);
3284  }
3285 
3286  generate_plane_rotation(H[iter_restart][iter_restart],
3287  H[iter_restart][iter_restart + 1],
3288  cs[iter_restart],
3289  sn[iter_restart]);
3290  apply_plane_rotation(H[iter_restart][iter_restart],
3291  H[iter_restart][iter_restart + 1],
3292  cs[iter_restart],
3293  sn[iter_restart]);
3294  apply_plane_rotation(s[iter_restart],
3295  s[iter_restart + 1],
3296  cs[iter_restart],
3297  sn[iter_restart]);
3298 
3299  // Compute the current residual
3300  beta = std::fabs(s[iter_restart + 1]);
3301 
3302  // compute relative residual
3303  resid = beta / normb;
3304 
3305  // DRAIG: Delete...
3306  // oomph_info << "Residual at iteration "
3307  // << iter << ": " << resid << std::endl;
3308 
3309  // if required will document convergence history to screen or file (if
3310  // stream open)
3312  {
3313  if (!Output_file_stream.is_open())
3314  {
3315  oomph_info << iter << " " << resid << std::endl;
3316  }
3317  else
3318  {
3319  Output_file_stream << iter << " " << resid << std::endl;
3320  }
3321  } // if (Doc_convergence_history)
3322 
3323  // If required tolerance found
3324  if (resid < Tolerance)
3325  {
3326  // update result vector
3327  update(iter_restart, H, s, v, solution);
3328 
3329  // Loop over the first n_dof entries of the RHS vector
3330  for (unsigned i = 0; i < n_dof; i++)
3331  {
3332  // Copy the i-th entry over
3333  lhs[i] = solution[i];
3334  }
3335 
3336  // Update the bifurcation parameter
3337  (*X_pt) -= solution[n_dof];
3338 
3339  // If we're meant to document convergence
3340  if (Doc_time)
3341  {
3342  // Output the convergence to screen
3343  oomph_info << "\nAugmentedProblemGMRES converged (1). Normalised "
3344  << "residual norm: " << resid
3345  << "\nNumber of iterations "
3346  << "to convergence: " << iter << "\n"
3347  << std::endl;
3348  }
3349 
3350  // Doc time for solver
3351  double t_end = TimingHelpers::timer();
3352  Solution_time = t_end - t_start;
3353 
3354  Iterations = iter;
3355 
3356  // If we're meant to document convergence
3357  if (Doc_time)
3358  {
3359  oomph_info
3360  << "Time for all preconditioner applications [sec]: "
3361  << t_prec_application_total
3362  << "\nTotal time for solve with AugmentedProblemGMRES [sec]: "
3363  << Solution_time << std::endl;
3364  }
3365 
3366  // We're done now so jump out here
3367  return;
3368  }
3369 #ifdef PARANOID
3370  // If the tolerance wasn't met
3371  else
3372  {
3373  // Warn the user if the sub-diagonal Hessenberg entry was almost
3374  // zero...
3375  if (std::fabs(H[iter_restart][iter_restart + 1]) < 1.0e-12)
3376  {
3377  // Create an output stream
3378  std::ostringstream warning_message_stream;
3379 
3380  // Create the warning message
3381  warning_message_stream << "Hessenberg subdiagonal entry (="
3382  << H[iter_restart][iter_restart + 1]
3383  << ") almost zero at iteration "
3384  << iter_restart << "\nbut residual "
3385  << "is only " << resid << " which does "
3386  << "not meet the tolerance (" << Tolerance
3387  << ")!" << std::endl;
3388 
3389  // Warn the user
3390  OomphLibWarning(warning_message_stream.str(),
3393  }
3394  } // if (resid<Tolerance)
3395 #endif
3396  } // for (iter_restart=0;iter_restart<Restart&&iter<=Max_iter;...
3397 
3398  // If we're not on the first iteration
3399  if (iter_restart > 0)
3400  {
3401  // Do an update
3402  update((iter_restart - 1), H, s, v, solution);
3403  }
3404 
3405  // Solve Mr = (b-Jx) for r
3406  {
3407  DoubleVector temp(aug_dist, 0.0);
3408  augmented_matrix_multiply(matrix_pt, solution, temp);
3409  double* temp_pt = temp.values_pt();
3410  const double* rhs_pt = rhs.values_pt();
3411  for (unsigned i = 0; i < n_dof; i++)
3412  {
3413  // Update the i-th entry of temp to be b-Jx
3414  temp_pt[i] = rhs_pt[i] - temp_pt[i];
3415  }
3416 
3417  // If we're using LHS preconditioning
3418  if (Preconditioner_LHS)
3419  {
3420  // Initialise timer
3421  double t_prec_application_start = TimingHelpers::timer();
3422 
3423  // Use the helper function to apply the Schur complement
3424  // preconditioner
3426 
3427  // Doc time for setup of preconditioner
3428  double t_prec_application_end = TimingHelpers::timer();
3429 
3430  // Update the preconditioner application time total
3431  t_prec_application_total +=
3432  (t_prec_application_end - t_prec_application_start);
3433  }
3434  } // Solve Mr = (b-Jx) for r
3435 
3436  // Compute the current residual
3437  beta = r.norm();
3438 
3439  // if relative residual within tolerance
3440  resid = beta / normb;
3441  if (resid < Tolerance)
3442  {
3443  // If we're meant to document convergence
3444  if (Doc_time)
3445  {
3446  oomph_info << "\nAugmentedProblemGMRES converged (2). Normalised "
3447  << "residual norm: " << resid << "\nNumber of iterations "
3448  << "to convergence: " << iter << "\n"
3449  << std::endl;
3450  }
3451 
3452  // Loop over the first n_dof entries of the RHS vector
3453  for (unsigned i = 0; i < n_dof; i++)
3454  {
3455  // Copy the i-th entry over
3456  lhs[i] = solution[i];
3457  }
3458 
3459  // Update the bifurcation parameter
3460  (*X_pt) -= solution[n_dof];
3461 
3462  // Doc time for solver
3463  double t_end = TimingHelpers::timer();
3464  Solution_time = t_end - t_start;
3465 
3466  Iterations = iter;
3467 
3468  // If we're meant to document convergence
3469  if (Doc_time)
3470  {
3471  oomph_info
3472  << "Time for all preconditioner applications [sec]: "
3473  << t_prec_application_total
3474  << "\nTotal time for solve with AugmentedProblemGMRES [sec]: "
3475  << Solution_time << std::endl;
3476  }
3477 
3478  return;
3479  } // if (resid<Tolerance)
3480  } // while (iter<=Max_iter)
3481 
3482  // DRAIG: Delete...
3483  {
3484  DoubleVector temp(aug_dist, 0.0);
3485  augmented_matrix_multiply(matrix_pt, solution, temp);
3486  temp *= -1.0;
3487  temp += rhs;
3488  resid = temp.norm() / normb;
3489  }
3490 
3491  // Loop over the first n_dof entries of the RHS vector
3492  for (unsigned i = 0; i < n_dof; i++)
3493  {
3494  // Copy the i-th entry over
3495  lhs[i] = solution[i];
3496  }
3497 
3498  // Update the bifurcation parameter
3499  (*X_pt) -= solution[n_dof];
3500 
3501  // Otherwise AugmentedProblemGMRES failed convergence
3502  oomph_info << "\nAugmentedProblemGMRES did not converge to required "
3503  << "tolerance!\nReturning with normalised residual norm: "
3504  << resid << "\nafter " << Max_iter << " iterations.\n"
3505  << std::endl;
3506 
3508  {
3509  std::string error_message_string = "Solver failed to converge and you ";
3510  error_message_string += "requested an error on convergence failures.";
3511  throw OomphLibError(
3512  error_message_string, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
3513  }
3514 
3515  return;
3516  } // End AugmentedProblemGMRES
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
MatrixXf H
Definition: HessenbergDecomposition_matrixH.cpp:4
RowVector3d w
Definition: Matrix_resize_int.cpp:3
void apply_plane_rotation(double &dx, double &dy, double &cs, double &sn)
Definition: iterative_linear_solver.h:1913
void update(const unsigned &k, const Vector< Vector< double >> &H, const Vector< double > &s, const Vector< DoubleVector > &v, DoubleVector &x)
Definition: iterative_linear_solver.h:1790
void apply_schur_complement_preconditioner(const DoubleVector &rhs, DoubleVector &soln)
Definition: iterative_linear_solver.h:1736
void generate_plane_rotation(double &dx, double &dy, double &cs, double &sn)
Definition: iterative_linear_solver.h:1868
void augmented_matrix_multiply(CRDoubleMatrix *matrix_pt, const DoubleVector &x, DoubleVector &soln)
Multiply the vector x by the augmented system matrix.
Definition: iterative_linear_solver.h:1697
bool distributed() const
distribution is serial or distributed
Definition: linear_algebra_distribution.h:493
unsigned nrow() const
access function to the number of global rows.
Definition: linear_algebra_distribution.h:463
double Tolerance
Convergence tolerance.
Definition: iterative_linear_solver.h:239
bool Throw_error_after_max_iter
Definition: iterative_linear_solver.h:262
double Preconditioner_setup_time
Preconditioner setup time.
Definition: iterative_linear_solver.h:254
unsigned Max_iter
Maximum number of iterations.
Definition: iterative_linear_solver.h:242
double Solution_time
linear solver solution time
Definition: iterative_linear_solver.h:251
std::ofstream Output_file_stream
Output file stream for convergence history.
Definition: iterative_linear_solver.h:231
bool Doc_convergence_history
Definition: iterative_linear_solver.h:228
bool Setup_preconditioner_before_solve
Definition: iterative_linear_solver.h:258
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
Definition: linear_algebra_distribution.h:335
void setup(DoubleMatrixBase *matrix_pt)
Definition: preconditioner.h:94
RealScalar s
Definition: level1_cplx_impl.h:130
Scalar beta
Definition: level2_cplx_impl.h:36
char char char int int * k
Definition: level2_impl.h:374
#define isnan(X)
Definition: main.h:109
r
Definition: UniformPSDSelfTest.py:20
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286

References apply_plane_rotation(), apply_schur_complement_preconditioner(), augmented_matrix_multiply(), B_pt, beta, oomph::DoubleVector::build(), oomph::DoubleVector::built(), C_pt, oomph::LinearAlgebraDistribution::communicator_pt(), oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), oomph::IterativeLinearSolver::Doc_convergence_history, oomph::LinearSolver::Doc_time, oomph::DoubleVector::dot(), boost::multiprecision::fabs(), generate_plane_rotation(), H, i, oomph::DoubleVector::initialise(), isnan, Iteration_restart, Iterations, k, oomph::IterativeLinearSolver::Max_iter, oomph::DoubleVector::norm(), oomph::DistributableLinearAlgebraObject::nrow(), oomph::DoubleMatrixBase::nrow(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::IterativeLinearSolver::Output_file_stream, Preconditioner_LHS, oomph::IterativeLinearSolver::preconditioner_pt(), oomph::IterativeLinearSolver::Preconditioner_setup_time, oomph::Preconditioner::preconditioner_solve(), UniformPSDSelfTest::r, Resolving, s, Schur_complement_scalar, oomph::Preconditioner::setup(), oomph::IterativeLinearSolver::Setup_preconditioner_before_solve, BiharmonicTestFunctions1::solution(), oomph::IterativeLinearSolver::Solution_time, oomph::Global_string_for_annotation::string(), oomph::IterativeLinearSolver::Throw_error_after_max_iter, oomph::TimingHelpers::timer(), oomph::IterativeLinearSolver::Tolerance, update(), v, oomph::DoubleVector::values_pt(), and w.

Referenced by solve().

◆ update()

void oomph::AugmentedProblemGMRES::update ( const unsigned k,
const Vector< Vector< double >> &  H,
const Vector< double > &  s,
const Vector< DoubleVector > &  v,
DoubleVector x 
)
inlineprivate

Helper function to update the result vector using the result, x=x_0+V_m*y

1795  {
1796  // Make a local copy of s
1797  Vector<double> y(s);
1798 
1799  // Backsolve:
1800  for (int i = int(k); i >= 0; i--)
1801  {
1802  // Divide the i-th entry of y by the i-th diagonal entry of H
1803  y[i] /= H[i][i];
1804 
1805  // Loop over the previous values of y and update
1806  for (int j = i - 1; j >= 0; j--)
1807  {
1808  // Update the j-th entry of y
1809  y[j] -= H[i][j] * y[i];
1810  }
1811  } // for (int i=int(k);i>=0;i--)
1812 
1813  // Store the number of rows in the result vector
1814  unsigned n_x = x.nrow();
1815 
1816  // Build a temporary vector with entries initialised to 0.0
1817  DoubleVector temp(x.distribution_pt(), 0.0);
1818 
1819  // Build a temporary vector with entries initialised to 0.0
1820  DoubleVector z(x.distribution_pt(), 0.0);
1821 
1822  // Get access to the underlying values
1823  double* temp_pt = temp.values_pt();
1824 
1825  // Calculate x=Vy
1826  for (unsigned j = 0; j <= k; j++)
1827  {
1828  // Get access to j-th column of v
1829  const double* vj_pt = v[j].values_pt();
1830 
1831  // Loop over the entries of the vector, temp
1832  for (unsigned i = 0; i < n_x; i++)
1833  {
1834  temp_pt[i] += vj_pt[i] * y[j];
1835  }
1836  } // for (unsigned j=0;j<=k;j++)
1837 
1838  // If we're using LHS preconditioning
1839  if (Preconditioner_LHS)
1840  {
1841  // Since we're using LHS preconditioning the preconditioner is applied
1842  // to the matrix and RHS vector so we simply update the value of x
1843  x += temp;
1844  }
1845  // If we're using RHS preconditioning
1846  else
1847  {
1848  // Since we're using RHS preconditioning the preconditioner is applied
1849  // to the solution vector
1851 
1852  // Use the update: x_m=x_0+inv(M)Vy [see Saad Y,"Iterative methods for
1853  // sparse linear systems", p.284]
1854  x += z;
1855  }
1856  } // End of update
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References apply_schur_complement_preconditioner(), H, i, j, k, Preconditioner_LHS, s, v, oomph::DoubleVector::values_pt(), plotDoE::x, and y.

Referenced by smc.smc::recursiveBayesian(), and solve_helper().

Member Data Documentation

◆ B_pt

DoubleVector* oomph::AugmentedProblemGMRES::B_pt
private

Pointer to the column vector in the bordered system.

Referenced by solve_helper().

◆ C_pt

DoubleVector* oomph::AugmentedProblemGMRES::C_pt
private

Pointer to the row vector in the bordered system.

Referenced by augmented_matrix_multiply(), and solve_helper().

◆ Iteration_restart

bool oomph::AugmentedProblemGMRES::Iteration_restart
private

boolean indicating if iteration restarting is used

Referenced by AugmentedProblemGMRES(), disable_iteration_restart(), enable_iteration_restart(), iteration_restart(), and solve_helper().

◆ Iterations

unsigned oomph::AugmentedProblemGMRES::Iterations
private

Number of iterations taken.

Referenced by iterations(), and solve_helper().

◆ Matrix_can_be_deleted

bool oomph::AugmentedProblemGMRES::Matrix_can_be_deleted
private

Boolean flag to indicate if the matrix pointed to be Matrix_pt can be deleted.

Referenced by clean_up_memory(), and solve().

◆ Matrix_pt

CRDoubleMatrix* oomph::AugmentedProblemGMRES::Matrix_pt
private

Pointer to matrix.

Referenced by clean_up_memory(), resolve(), and solve().

◆ Preconditioner_LHS

bool oomph::AugmentedProblemGMRES::Preconditioner_LHS
private

boolean indicating use of left hand preconditioning (if true) or right hand preconditioning (if false)

Referenced by AugmentedProblemGMRES(), set_preconditioner_LHS(), set_preconditioner_RHS(), solve_helper(), and update().

◆ Resolving

bool oomph::AugmentedProblemGMRES::Resolving
private

Boolean flag to indicate if the solve is done in re-solve mode, bypassing setup of matrix and preconditioner

Referenced by resolve(), solve(), and solve_helper().

◆ Restart

unsigned oomph::AugmentedProblemGMRES::Restart
private

The number of iterations before the iteration proceedure is restarted if iteration restart is used

◆ Rhs_pt

double* oomph::AugmentedProblemGMRES::Rhs_pt
private

Pointer to the last entry of the RHS vector in the bordered system.

◆ Schur_complement_scalar

double oomph::AugmentedProblemGMRES::Schur_complement_scalar
private

The scalar component of the Schur complement preconditioner.

Referenced by apply_schur_complement_preconditioner(), solve(), and solve_helper().

◆ X_pt

double* oomph::AugmentedProblemGMRES::X_pt
private

Pointer to the last entry of the LHS vector in the bordered system.


The documentation for this class was generated from the following files: