oomph::GMRES< MATRIX > Class Template Reference

The GMRES method. More...

#include <iterative_linear_solver.h>

+ Inheritance diagram for oomph::GMRES< MATRIX >:

Public Member Functions

 GMRES ()
 Constructor. More...
 
virtual ~GMRES ()
 Destructor (cleanup storage) More...
 
 GMRES (const GMRES &)=delete
 Broken copy constructor. More...
 
void operator= (const GMRES &)=delete
 Broken assignment operator. More...
 
void disable_resolve ()
 Overload disable resolve so that it cleans up memory too. More...
 
void enable_computation_of_gradient ()
 function to enable the computation of the gradient 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)
 
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 solve_helper (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
 General interface to solve function. More...
 
void clean_up_memory ()
 Cleanup data that's stored for resolve (if any has been stored) 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...
 
MATRIX * Matrix_pt
 Pointer to matrix. More...
 
bool Resolving
 
bool Matrix_can_be_deleted
 
bool Preconditioner_LHS
 
double Preconditioner_application_time
 Storage for the time spent applying the preconditioner. More...
 

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

template<typename MATRIX>
class oomph::GMRES< MATRIX >

The GMRES method.

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

Constructor & Destructor Documentation

◆ GMRES() [1/2]

template<typename MATRIX >
oomph::GMRES< MATRIX >::GMRES ( )
inline

Constructor.

1231  : Iterations(0),
1232  Matrix_pt(0),
1233  Resolving(false),
1234  Matrix_can_be_deleted(true),
1236  {
1237  Preconditioner_LHS = true;
1238  Iteration_restart = false;
1239  }
bool Resolving
Definition: iterative_linear_solver.h:1525
bool Preconditioner_LHS
Definition: iterative_linear_solver.h:1533
double Preconditioner_application_time
Storage for the time spent applying the preconditioner.
Definition: iterative_linear_solver.h:1536
MATRIX * Matrix_pt
Pointer to matrix.
Definition: iterative_linear_solver.h:1521
bool Matrix_can_be_deleted
Definition: iterative_linear_solver.h:1529
unsigned Iterations
Number of iterations taken.
Definition: iterative_linear_solver.h:1511
bool Iteration_restart
boolean indicating if iteration restarting is used
Definition: iterative_linear_solver.h:1518

References oomph::GMRES< MATRIX >::Iteration_restart, and oomph::GMRES< MATRIX >::Preconditioner_LHS.

◆ ~GMRES()

template<typename MATRIX >
virtual oomph::GMRES< MATRIX >::~GMRES ( )
inlinevirtual

Destructor (cleanup storage)

1243  {
1244  clean_up_memory();
1245  }
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
Definition: iterative_linear_solver.h:1357

References oomph::GMRES< MATRIX >::clean_up_memory().

◆ GMRES() [2/2]

template<typename MATRIX >
oomph::GMRES< MATRIX >::GMRES ( const GMRES< MATRIX > &  )
delete

Broken copy constructor.

Member Function Documentation

◆ apply_plane_rotation()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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}. \]

1499  {
1500  // Calculate the value of dx but don't update it yet
1501  double temp = cs * dx + sn * dy;
1502 
1503  // Set the value of dy
1504  dy = -sn * dx + cs * dy;
1505 
1506  // Set the value of dx using the correct values of dx and dy
1507  dx = temp;
1508  }

◆ clean_up_memory()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::clean_up_memory ( )
inlineprivatevirtual

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

Reimplemented from oomph::LinearSolver.

1358  {
1359  if ((Matrix_pt != 0) && (Matrix_can_be_deleted))
1360  {
1361  delete Matrix_pt;
1362  Matrix_pt = 0;
1363  }
1364  }

References oomph::GMRES< MATRIX >::Matrix_can_be_deleted, and oomph::GMRES< MATRIX >::Matrix_pt.

Referenced by oomph::GMRES< MATRIX >::disable_resolve(), and oomph::GMRES< MATRIX >::~GMRES().

◆ disable_iteration_restart()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::disable_iteration_restart ( )
inline

switches off iteration restart

1334  {
1335  Iteration_restart = false;
1336  }

References oomph::GMRES< MATRIX >::Iteration_restart.

◆ disable_resolve()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::disable_resolve ( )
inlinevirtual

Overload disable resolve so that it cleans up memory too.

Reimplemented from oomph::LinearSolver.

1255  {
1257  clean_up_memory();
1258  }
virtual void disable_resolve()
Definition: linear_solver.h:144

References oomph::GMRES< MATRIX >::clean_up_memory(), and oomph::LinearSolver::disable_resolve().

◆ enable_computation_of_gradient()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::enable_computation_of_gradient ( )
inlinevirtual

function to enable the computation of the gradient

Reimplemented from oomph::LinearSolver.

1262  {
1263  Compute_gradient = true;
1264  }
bool Compute_gradient
Definition: linear_solver.h:81

References oomph::LinearSolver::Compute_gradient.

◆ enable_iteration_restart()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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

1327  {
1328  Restart = restart;
1329  Iteration_restart = true;
1330  }
Definition: flowRule_restart.cpp:8
Definition: restart2.cpp:8

References oomph::GMRES< MATRIX >::Iteration_restart.

◆ generate_plane_rotation()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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

1454  {
1455  // If dy=0 then we do not need to apply a rotation
1456  if (dy == 0.0)
1457  {
1458  // Using theta=0 gives cos(theta)=1
1459  cs = 1.0;
1460 
1461  // Using theta=0 gives sin(theta)=0
1462  sn = 0.0;
1463  }
1464  // If dx or dy is large using the normal form of calculting cs and sn
1465  // is naive since this may overflow or underflow so instead we calculate
1466  // r=sqrt(pow(dx,2)+pow(dy,2)) by using r=|dy|sqrt(1+pow(dx/dy,2)) if
1467  // |dy|>|dx| [see <A
1468  // HREF=https://en.wikipedia.org/wiki/Hypot">Hypot</A>.].
1469  else if (fabs(dy) > fabs(dx))
1470  {
1471  // Since |dy|>|dx| calculate the ratio dx/dy
1472  double temp = dx / dy;
1473 
1474  // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))
1475  sn = 1.0 / sqrt(1.0 + temp * temp);
1476 
1477  // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))=(dx/dy)*sin(theta)
1478  cs = temp * sn;
1479  }
1480  // Otherwise, we have |dx|>=|dy| so to, again, avoid overflow or underflow
1481  // calculate the values of cs and sn using the method above
1482  else
1483  {
1484  // Since |dx|>=|dy| calculate the ratio dy/dx
1485  double temp = dy / dx;
1486 
1487  // Calculate cos(theta)=dx/sqrt(pow(dx,2)+pow(dy,2))
1488  cs = 1.0 / sqrt(1.0 + temp * temp);
1489 
1490  // Calculate sin(theta)=dy/sqrt(pow(dx,2)+pow(dy,2))=(dy/dx)*cos(theta)
1491  sn = temp * cs;
1492  }
1493  } // 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().

◆ iteration_restart()

template<typename MATRIX >
bool oomph::GMRES< MATRIX >::iteration_restart ( ) const
inline

access function indicating whether restarted GMRES is used

1319  {
1320  return Iteration_restart;
1321  }

References oomph::GMRES< MATRIX >::Iteration_restart.

◆ iterations()

template<typename MATRIX >
unsigned oomph::GMRES< MATRIX >::iterations ( ) const
inlinevirtual

Number of iterations taken.

Implements oomph::IterativeLinearSolver.

1313  {
1314  return Iterations;
1315  }

References oomph::GMRES< MATRIX >::Iterations.

◆ operator=()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::operator= ( const GMRES< MATRIX > &  )
delete

Broken assignment operator.

◆ resolve()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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.

2134  {
2135  // We are re-solving
2136  Resolving = true;
2137 
2138 #ifdef PARANOID
2139  if (Matrix_pt == 0)
2140  {
2141  throw OomphLibError("No matrix was stored -- cannot re-solve",
2144  }
2145 #endif
2146 
2147  // Call linear algebra-style solver
2148  this->solve(Matrix_pt, rhs, result);
2149 
2150  // Reset re-solving flag
2151  Resolving = false;
2152  }
void solve(Problem *const &problem_pt, DoubleVector &result)
Definition: iterative_linear_solver.cc:2161
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and solve.

◆ set_preconditioner_LHS()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::set_preconditioner_LHS ( )
inline

Set left preconditioning (the default)

1340  {
1341  Preconditioner_LHS = true;
1342  }

References oomph::GMRES< MATRIX >::Preconditioner_LHS.

◆ set_preconditioner_RHS()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::set_preconditioner_RHS ( )
inline

Enable right preconditioning.

1346  {
1347  Preconditioner_LHS = false;
1348  }

References oomph::GMRES< MATRIX >::Preconditioner_LHS.

◆ solve() [1/3]

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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.

1276  {
1277  // setup the distribution
1278  this->build_distribution(rhs.distribution_pt());
1279 
1280  // Store the matrix if required
1281  if ((Enable_resolve) && (!Resolving))
1282  {
1283  Matrix_pt = dynamic_cast<MATRIX*>(matrix_pt);
1284 
1285  // Matrix has been passed in from the outside so we must not
1286  // delete it
1287  Matrix_can_be_deleted = false;
1288  }
1289 
1290  // Call the helper function
1291  this->solve_helper(matrix_pt, rhs, solution);
1292  }
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
Definition: linear_algebra_distribution.h:507
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
Definition: iterative_linear_solver.cc:2250
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, oomph::GMRES< MATRIX >::Matrix_can_be_deleted, oomph::GMRES< MATRIX >::Matrix_pt, oomph::GMRES< MATRIX >::Resolving, BiharmonicTestFunctions1::solution(), and oomph::GMRES< MATRIX >::solve_helper().

◆ solve() [2/3]

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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.

1302  {
1303  LinearSolver::solve(matrix_pt, rhs, result);
1304  }
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0

References oomph::LinearSolver::solve().

◆ solve() [3/3]

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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.

Implements oomph::LinearSolver.

2162  {
2163  // Find # of degrees of freedom (variables)
2164  unsigned n_dof = problem_pt->ndof();
2165 
2166  // Initialise timer
2167  double t_start = TimingHelpers::timer();
2168 
2169  // We're not re-solving
2170  Resolving = false;
2171 
2172  // Get rid of any previously stored data
2173  clean_up_memory();
2174 
2175  // setup the distribution
2176  LinearAlgebraDistribution dist(problem_pt->communicator_pt(), n_dof, false);
2177  this->build_distribution(dist);
2178 
2179  // Get Jacobian matrix in format specified by template parameter
2180  // and nonlinear residual vector
2181  Matrix_pt = new MATRIX;
2182  DoubleVector f;
2183  if (dynamic_cast<DistributableLinearAlgebraObject*>(Matrix_pt) != 0)
2184  {
2185  if (dynamic_cast<CRDoubleMatrix*>(Matrix_pt) != 0)
2186  {
2187  dynamic_cast<CRDoubleMatrix*>(Matrix_pt)->build(
2188  this->distribution_pt());
2189  f.build(this->distribution_pt(), 0.0);
2190  }
2191  }
2192  problem_pt->get_jacobian(f, *Matrix_pt);
2193 
2194  // We've made the matrix, we can delete it...
2195  Matrix_can_be_deleted = true;
2196 
2197  // Doc time for setup
2198  double t_end = TimingHelpers::timer();
2199  Jacobian_setup_time = t_end - t_start;
2200 
2201  if (Doc_time)
2202  {
2203  oomph_info << "Time for setup of Jacobian [sec]: " << Jacobian_setup_time
2204  << std::endl;
2205  }
2206 
2207  // If we want to compute the gradient for the globally convergent
2208  // Newton method, then do it here
2209  if (Compute_gradient)
2210  {
2211  // Compute it
2212  Matrix_pt->multiply_transpose(f, Gradient_for_glob_conv_newton_solve);
2213  // Set the flag
2215  }
2216 
2217  // Call linear algebra-style solver
2218  // If the result distribution is wrong, then redistribute
2219  // before the solve and return to original distribution
2220  // afterwards
2221  if ((result.built()) &&
2222  (!(*result.distribution_pt() == *this->distribution_pt())))
2223  {
2224  LinearAlgebraDistribution temp_global_dist(result.distribution_pt());
2225  result.build(this->distribution_pt(), 0.0);
2226  this->solve_helper(Matrix_pt, f, result);
2227  result.redistribute(&temp_global_dist);
2228  }
2229  // Otherwise just solve
2230  else
2231  {
2232  this->solve_helper(Matrix_pt, f, result);
2233  }
2234 
2235  // Kill matrix unless it's still required for resolve
2237  };
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
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
bool Gradient_has_been_computed
flag that indicates whether the gradient was computed or not
Definition: linear_solver.h:84
DoubleVector Gradient_for_glob_conv_newton_solve
Definition: linear_solver.h:88
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::DoubleVector::built(), oomph::TerminateHelper::clean_up_memory(), oomph::Problem::communicator_pt(), oomph::DistributableLinearAlgebraObject::distribution_pt(), f(), oomph::Problem::get_jacobian(), oomph::Problem::ndof(), oomph::oomph_info, oomph::DoubleVector::redistribute(), and oomph::TimingHelpers::timer().

◆ solve_helper()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::solve_helper ( DoubleMatrixBase *const &  matrix_pt,
const DoubleVector rhs,
DoubleVector solution 
)
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++/

2253  {
2254  // Get number of dofs
2255  unsigned n_dof = rhs.nrow();
2256 
2257 #ifdef PARANOID
2258  // PARANOID check that if the matrix is distributable then it should not be
2259  // then it should not be distributed
2260  if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt) != 0)
2261  {
2262  if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt)
2263  ->distributed())
2264  {
2265  std::ostringstream error_message_stream;
2266  error_message_stream << "The matrix must not be distributed.";
2267  throw OomphLibError(error_message_stream.str(),
2270  }
2271  }
2272  // PARANOID check that this rhs distribution is setup
2273  if (!rhs.built())
2274  {
2275  std::ostringstream error_message_stream;
2276  error_message_stream << "The rhs vector distribution must be setup.";
2277  throw OomphLibError(error_message_stream.str(),
2280  }
2281  // PARANOID check that the rhs has the right number of global rows
2282  if (rhs.nrow() != n_dof)
2283  {
2284  throw OomphLibError(
2285  "RHS does not have the same dimension as the linear system",
2288  }
2289  // PARANOID check that the rhs is not distributed
2290  if (rhs.distribution_pt()->distributed())
2291  {
2292  std::ostringstream error_message_stream;
2293  error_message_stream << "The rhs vector must not be distributed.";
2294  throw OomphLibError(error_message_stream.str(),
2297  }
2298  // PARANOID check that if the result is setup it matches the distribution
2299  // of the rhs
2300  if (solution.built())
2301  {
2302  if (!(*rhs.distribution_pt() == *solution.distribution_pt()))
2303  {
2304  std::ostringstream error_message_stream;
2305  error_message_stream << "If the result distribution is setup then it "
2306  "must be the same as the "
2307  << "rhs distribution";
2308  throw OomphLibError(error_message_stream.str(),
2311  }
2312  }
2313 #endif
2314 
2315  // Reset the time spent applying the preconditioner
2317 
2318  // Set up the solution if it is not
2319  if (!solution.built())
2320  {
2321  solution.build(this->distribution_pt(), 0.0);
2322  }
2323  // Otherwise initialise to zero
2324  else
2325  {
2326  solution.initialise(0.0);
2327  }
2328 
2329  // Time solver
2330  double t_start = TimingHelpers::timer();
2331 
2332  // Relative residual
2333  double resid;
2334 
2335  // iteration counter
2336  unsigned iter = 1;
2337 
2338  // if not using iteration restart set Restart to n_dof
2339  if (!Iteration_restart)
2340  {
2341  Restart = n_dof;
2342  }
2343 
2344  // initialise vectors
2345  Vector<double> s(Restart + 1, 0);
2346  Vector<double> cs(Restart + 1);
2347  Vector<double> sn(Restart + 1);
2348  DoubleVector w(this->distribution_pt(), 0.0);
2349 
2350  // Setup preconditioner only if we're not re-solving
2351  if (!Resolving)
2352  {
2353  // only setup the preconditioner before solve if require
2355  {
2356  // Setup preconditioner from the Jacobian matrix
2357  double t_start_prec = TimingHelpers::timer();
2358 
2359  // do not setup
2360  preconditioner_pt()->setup(matrix_pt);
2361 
2362  // Doc time for setup of preconditioner
2363  double t_end_prec = TimingHelpers::timer();
2364  Preconditioner_setup_time = t_end_prec - t_start_prec;
2365 
2366  if (Doc_time)
2367  {
2368  oomph_info << "Time for setup of preconditioner [sec]: "
2369  << Preconditioner_setup_time << std::endl;
2370  }
2371  }
2372  }
2373  else
2374  {
2375  if (Doc_time)
2376  {
2377  oomph_info << "Setup of preconditioner is bypassed in resolve mode"
2378  << std::endl;
2379  }
2380  }
2381 
2382  // solve b-Jx = Mr for r (assumes x = 0);
2383  DoubleVector r(this->distribution_pt(), 0.0);
2384  if (Preconditioner_LHS)
2385  {
2386  // Start the timer
2387  double t_start_prec = TimingHelpers::timer();
2388 
2389  // Apply the preconditioner
2391 
2392  // Calculate the time taken for the preconditioner solve
2394  (TimingHelpers::timer() - t_start_prec);
2395  }
2396  else
2397  {
2398  r = rhs;
2399  }
2400  double normb = 0;
2401 
2402  // compute norm(r)
2403  double* r_pt = r.values_pt();
2404  for (unsigned i = 0; i < n_dof; i++)
2405  {
2406  normb += r_pt[i] * r_pt[i];
2407  }
2408  normb = sqrt(normb);
2409 
2410  // set beta (the initial residual)
2411  double beta = normb;
2412 
2413  // compute initial relative residual
2414  if (normb == 0.0) normb = 1;
2415  resid = beta / normb;
2416 
2417  // if required will document convergence history to screen or file (if
2418  // stream open)
2420  {
2421  if (!Output_file_stream.is_open())
2422  {
2423  oomph_info << 0 << " " << resid << std::endl;
2424  }
2425  else
2426  {
2427  Output_file_stream << 0 << " " << resid << std::endl;
2428  }
2429  }
2430 
2431  // if GMRES converges immediately
2432  if (resid <= Tolerance)
2433  {
2434  if (Doc_time)
2435  {
2436  oomph_info << "GMRES converged immediately. Normalised residual norm: "
2437  << resid << std::endl;
2438  }
2439  // Doc time for solver
2440  double t_end = TimingHelpers::timer();
2441  Solution_time = t_end - t_start;
2442 
2443  if (Doc_time)
2444  {
2445  // Doc the time taken for the preconditioner applications
2446  oomph_info << "Time for all preconditioner applications [sec]: "
2448  << "\n\nTime for solve with GMRES [sec]: " << Solution_time
2449  << std::endl;
2450  }
2451  return;
2452  }
2453 
2454 
2455  // initialise vector of orthogonal basis vectors (v) and upper hessenberg
2456  // matrix H
2457  // NOTE: for implementation purpose the upper hessenberg matrix indexes are
2458  // are swapped so the matrix is effectively transposed
2459  Vector<DoubleVector> v;
2460  v.resize(Restart + 1);
2461  Vector<Vector<double>> H(Restart + 1);
2462 
2463  // while...
2464  while (iter <= Max_iter)
2465  {
2466  // set zeroth basis vector v[0] to r/beta
2467  v[0].build(this->distribution_pt(), 0.0);
2468  double* v0_pt = v[0].values_pt();
2469  for (unsigned i = 0; i < n_dof; i++)
2470  {
2471  v0_pt[i] = r_pt[i] / beta;
2472  }
2473 
2474  //
2475  s[0] = beta;
2476 
2477  // inner iteration counter for restarted version
2478  unsigned iter_restart;
2479 
2480  // perform iterations
2481  for (iter_restart = 0; iter_restart < Restart && iter <= Max_iter;
2482  iter_restart++, iter++)
2483  {
2484  // resize next column of upper hessenberg matrix
2485  H[iter_restart].resize(iter_restart + 2);
2486 
2487  // solve Jv[i] = Mw for w
2488  {
2489  DoubleVector temp(this->distribution_pt(), 0.0);
2490  if (Preconditioner_LHS)
2491  {
2492  // solve Jv[i] = Mw for w
2493  matrix_pt->multiply(v[iter_restart], temp);
2494 
2495  // Start the timer
2496  double t_start_prec = TimingHelpers::timer();
2497 
2498  // Apply the preconditioner
2500 
2501  // Calculate the time taken for the preconditioner solve
2503  (TimingHelpers::timer() - t_start_prec);
2504  }
2505  else
2506  {
2507  // Start the timer
2508  double t_start_prec = TimingHelpers::timer();
2509 
2510  // w=JM^{-1}v by saad p270
2511  preconditioner_pt()->preconditioner_solve(v[iter_restart], temp);
2512 
2513  // Calculate the time taken for the preconditioner solve
2515  (TimingHelpers::timer() - t_start_prec);
2516 
2517  // Do a matrix multiplication
2518  matrix_pt->multiply(temp, w);
2519  }
2520  }
2521 
2522  //
2523  double* w_pt = w.values_pt();
2524  for (unsigned k = 0; k <= iter_restart; k++)
2525  {
2526  //
2527  H[iter_restart][k] = 0.0;
2528  double* vk_pt = v[k].values_pt();
2529  for (unsigned i = 0; i < n_dof; i++)
2530  {
2531  H[iter_restart][k] += w_pt[i] * vk_pt[i];
2532  }
2533 
2534  //
2535  for (unsigned i = 0; i < n_dof; i++)
2536  {
2537  w_pt[i] -= H[iter_restart][k] * vk_pt[i];
2538  }
2539  }
2540 
2541  //
2542  {
2543  double temp_norm_w = 0.0;
2544  for (unsigned i = 0; i < n_dof; i++)
2545  {
2546  temp_norm_w += w_pt[i] * w_pt[i];
2547  }
2548  temp_norm_w = sqrt(temp_norm_w);
2549  H[iter_restart][iter_restart + 1] = temp_norm_w;
2550  }
2551 
2552  //
2553  v[iter_restart + 1].build(this->distribution_pt(), 0.0);
2554  double* v_pt = v[iter_restart + 1].values_pt();
2555  for (unsigned i = 0; i < n_dof; i++)
2556  {
2557  v_pt[i] = w_pt[i] / H[iter_restart][iter_restart + 1];
2558  }
2559 
2560  //
2561  for (unsigned k = 0; k < iter_restart; k++)
2562  {
2564  H[iter_restart][k], H[iter_restart][k + 1], cs[k], sn[k]);
2565  }
2566  generate_plane_rotation(H[iter_restart][iter_restart],
2567  H[iter_restart][iter_restart + 1],
2568  cs[iter_restart],
2569  sn[iter_restart]);
2570  apply_plane_rotation(H[iter_restart][iter_restart],
2571  H[iter_restart][iter_restart + 1],
2572  cs[iter_restart],
2573  sn[iter_restart]);
2574  apply_plane_rotation(s[iter_restart],
2575  s[iter_restart + 1],
2576  cs[iter_restart],
2577  sn[iter_restart]);
2578 
2579  // compute current residual
2580  beta = std::fabs(s[iter_restart + 1]);
2581 
2582  // compute relative residual
2583  resid = beta / normb;
2584 
2585  // if required will document convergence history to screen or file (if
2586  // stream open)
2588  {
2589  if (!Output_file_stream.is_open())
2590  {
2591  oomph_info << iter << " " << resid << std::endl;
2592  }
2593  else
2594  {
2595  Output_file_stream << iter << " " << resid << std::endl;
2596  }
2597  }
2598 
2599  // if required tolerance found
2600  if (resid < Tolerance)
2601  {
2602  // update result vector
2603  update(iter_restart, H, s, v, solution);
2604 
2605  // document convergence
2606  if (Doc_time)
2607  {
2608  oomph_info << std::endl;
2609  oomph_info << "GMRES converged (1). Normalised residual norm: "
2610  << resid << std::endl;
2611  oomph_info << "Number of iterations to convergence: " << iter
2612  << std::endl;
2613  oomph_info << std::endl;
2614  }
2615 
2616  // Doc time for solver
2617  double t_end = TimingHelpers::timer();
2618  Solution_time = t_end - t_start;
2619 
2620  Iterations = iter;
2621 
2622  if (Doc_time)
2623  {
2624  // Doc the time taken for the preconditioner applications
2625  oomph_info << "Time for all preconditioner applications [sec]: "
2627  << "\n\nTime for solve with GMRES [sec]: "
2628  << Solution_time << std::endl;
2629  }
2630  return;
2631  }
2632  }
2633 
2634  // update
2635  if (iter_restart > 0) update((iter_restart - 1), H, s, v, solution);
2636 
2637  // solve Mr = (b-Jx) for r
2638  {
2639  DoubleVector temp(this->distribution_pt(), 0.0);
2640  matrix_pt->multiply(solution, temp);
2641  double* temp_pt = temp.values_pt();
2642  const double* rhs_pt = rhs.values_pt();
2643  for (unsigned i = 0; i < n_dof; i++)
2644  {
2645  temp_pt[i] = rhs_pt[i] - temp_pt[i];
2646  }
2647 
2648  if (Preconditioner_LHS)
2649  {
2650  // Start the timer
2651  double t_start_prec = TimingHelpers::timer();
2652 
2654 
2655  // Calculate the time taken for the preconditioner solve
2657  (TimingHelpers::timer() - t_start_prec);
2658  }
2659  }
2660 
2661  // compute current residual
2662  beta = 0.0;
2663  r_pt = r.values_pt();
2664  for (unsigned i = 0; i < n_dof; i++)
2665  {
2666  beta += r_pt[i] * r_pt[i];
2667  }
2668  beta = sqrt(beta);
2669 
2670  // if relative residual within tolerance
2671  resid = beta / normb;
2672  if (resid < Tolerance)
2673  {
2674  if (Doc_time)
2675  {
2676  oomph_info << std::endl;
2677  oomph_info << "GMRES converged (2). Normalised residual norm: "
2678  << resid << std::endl;
2679  oomph_info << "Number of iterations to convergence: " << iter
2680  << std::endl;
2681  oomph_info << std::endl;
2682  }
2683 
2684  // Doc time for solver
2685  double t_end = TimingHelpers::timer();
2686  Solution_time = t_end - t_start;
2687 
2688  Iterations = iter;
2689 
2690  if (Doc_time)
2691  {
2692  // Doc the time taken for the preconditioner applications
2693  oomph_info << "Time for all preconditioner applications [sec]: "
2695  << "\n\nTime for solve with GMRES [sec]: "
2696  << Solution_time << std::endl;
2697  }
2698  return;
2699  }
2700  }
2701 
2702  // DRAIG: I want to delete this but GMRES doesn't compute the residuals
2703  // properly after this scope when it doesn't converge within the specified
2704  // number of iterations. Not sure why. If you're bored, try to figure
2705  // out why.
2706  {
2707  DoubleVector temp(this->distribution_pt(), 0.0);
2708  matrix_pt->multiply(solution, temp);
2709  temp *= -1.0;
2710  temp += rhs;
2711  resid = temp.norm() / normb;
2712  }
2713 
2714  // otherwise GMRES failed convergence
2715  oomph_info << std::endl;
2716  oomph_info << "GMRES did not converge to required tolerance! " << std::endl;
2717  oomph_info << "Returning with normalised residual norm: " << resid
2718  << std::endl;
2719  oomph_info << "after " << Max_iter << " iterations." << std::endl;
2720  oomph_info << std::endl;
2721 
2722 
2724  {
2725  std::string err = "Solver failed to converge and you requested an error";
2726  err += " on convergence failures.";
2727  throw OomphLibError(
2729  }
2730 
2731  return;
2732 
2733  } // End GMRES
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
int i
Definition: BiCGSTAB_step_by_step.cpp:9
MatrixXf H
Definition: HessenbergDecomposition_matrixH.cpp:4
RowVector3d w
Definition: Matrix_resize_int.cpp:3
bool distributed() const
distribution is serial or distributed
Definition: linear_algebra_distribution.h:493
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:1368
void apply_plane_rotation(double &dx, double &dy, double &cs, double &sn)
Definition: iterative_linear_solver.h:1498
void generate_plane_rotation(double &dx, double &dy, double &cs, double &sn)
Definition: iterative_linear_solver.h:1453
double Tolerance
Convergence tolerance.
Definition: iterative_linear_solver.h:239
bool Throw_error_after_max_iter
Definition: iterative_linear_solver.h:262
Preconditioner *& preconditioner_pt()
Access function to preconditioner.
Definition: iterative_linear_solver.h:95
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
void setup(DoubleMatrixBase *matrix_pt)
Definition: preconditioner.h:94
virtual void preconditioner_solve(const DoubleVector &r, DoubleVector &z)=0
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
r
Definition: UniformPSDSelfTest.py:20
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286

References beta, oomph::DoubleVector::built(), oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), boost::multiprecision::fabs(), H, i, Global_Variables::Iterations, k, oomph::BlackBoxFDNewtonSolver::Max_iter, oomph::DoubleMatrixBase::multiply(), oomph::DoubleVector::norm(), oomph::DistributableLinearAlgebraObject::nrow(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, UniformPSDSelfTest::r, s, BiharmonicTestFunctions1::solution(), sqrt(), oomph::Global_string_for_annotation::string(), oomph::TimingHelpers::timer(), v, oomph::DoubleVector::values_pt(), and w.

Referenced by oomph::GMRES< MATRIX >::solve().

◆ update()

template<typename MATRIX >
void oomph::GMRES< MATRIX >::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

1373  {
1374  // Make a local copy of s
1375  Vector<double> y(s);
1376 
1377  // Backsolve:
1378  for (int i = int(k); i >= 0; i--)
1379  {
1380  // Divide the i-th entry of y by the i-th diagonal entry of H
1381  y[i] /= H[i][i];
1382 
1383  // Loop over the previous values of y and update
1384  for (int j = i - 1; j >= 0; j--)
1385  {
1386  // Update the j-th entry of y
1387  y[j] -= H[i][j] * y[i];
1388  }
1389  } // for (int i=int(k);i>=0;i--)
1390 
1391  // Store the number of rows in the result vector
1392  unsigned n_x = x.nrow();
1393 
1394  // Build a temporary vector with entries initialised to 0.0
1395  DoubleVector temp(x.distribution_pt(), 0.0);
1396 
1397  // Build a temporary vector with entries initialised to 0.0
1398  DoubleVector z(x.distribution_pt(), 0.0);
1399 
1400  // Get access to the underlying values
1401  double* temp_pt = temp.values_pt();
1402 
1403  // Calculate x=Vy
1404  for (unsigned j = 0; j <= k; j++)
1405  {
1406  // Get access to j-th column of v
1407  const double* vj_pt = v[j].values_pt();
1408 
1409  // Loop over the entries of the vector, temp
1410  for (unsigned i = 0; i < n_x; i++)
1411  {
1412  temp_pt[i] += vj_pt[i] * y[j];
1413  }
1414  } // for (unsigned j=0;j<=k;j++)
1415 
1416  // If we're using LHS preconditioning
1417  if (Preconditioner_LHS)
1418  {
1419  // Since we're using LHS preconditioning the preconditioner is applied
1420  // to the matrix and RHS vector so we simply update the value of x
1421  x += temp;
1422  }
1423  // If we're using RHS preconditioning
1424  else
1425  {
1426  // Start the timer
1427  double t_start_prec = TimingHelpers::timer();
1428 
1429  // Since we're using RHS preconditioning the preconditioner is applied
1430  // to the solution vector
1432 
1433  // Calculate the time taken for the preconditioner solve
1435  (TimingHelpers::timer() - t_start_prec);
1436 
1437  // Use the update: x_m=x_0+inv(M)Vy [see Saad Y,"Iterative methods for
1438  // sparse linear systems", p.284]
1439  x += z;
1440  }
1441  } // End of update
Scalar * y
Definition: level1_cplx_impl.h:128
list x
Definition: plotDoE.py:28
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References H, i, j, k, oomph::GMRES< MATRIX >::Preconditioner_application_time, oomph::GMRES< MATRIX >::Preconditioner_LHS, oomph::IterativeLinearSolver::preconditioner_pt(), oomph::Preconditioner::preconditioner_solve(), s, oomph::TimingHelpers::timer(), v, oomph::DoubleVector::values_pt(), plotDoE::x, and y.

Referenced by smc.smc::recursiveBayesian().

Member Data Documentation

◆ Iteration_restart

template<typename MATRIX >
bool oomph::GMRES< MATRIX >::Iteration_restart
private

◆ Iterations

template<typename MATRIX >
unsigned oomph::GMRES< MATRIX >::Iterations
private

Number of iterations taken.

Referenced by oomph::GMRES< MATRIX >::iterations().

◆ Matrix_can_be_deleted

template<typename MATRIX >
bool oomph::GMRES< MATRIX >::Matrix_can_be_deleted
private

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

Referenced by oomph::GMRES< MATRIX >::clean_up_memory(), and oomph::GMRES< MATRIX >::solve().

◆ Matrix_pt

template<typename MATRIX >
MATRIX* oomph::GMRES< MATRIX >::Matrix_pt
private

◆ Preconditioner_application_time

template<typename MATRIX >
double oomph::GMRES< MATRIX >::Preconditioner_application_time
private

Storage for the time spent applying the preconditioner.

Referenced by oomph::GMRES< MATRIX >::update().

◆ Preconditioner_LHS

template<typename MATRIX >
bool oomph::GMRES< MATRIX >::Preconditioner_LHS
private

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

Referenced by oomph::GMRES< MATRIX >::GMRES(), oomph::GMRES< MATRIX >::set_preconditioner_LHS(), oomph::GMRES< MATRIX >::set_preconditioner_RHS(), and oomph::GMRES< MATRIX >::update().

◆ Resolving

template<typename MATRIX >
bool oomph::GMRES< MATRIX >::Resolving
private

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

Referenced by oomph::GMRES< MATRIX >::solve().

◆ Restart

template<typename MATRIX >
unsigned oomph::GMRES< MATRIX >::Restart
private

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


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