oomph::HelmholtzFGMRESMG< MATRIX > Class Template Reference

#include <complex_smoother.h>

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

Public Member Functions

 HelmholtzFGMRESMG ()
 Constructor (empty) More...
 
virtual ~HelmholtzFGMRESMG ()
 Destructor (cleanup storage) More...
 
 HelmholtzFGMRESMG (const HelmholtzFGMRESMG &)=delete
 Broken copy constructor. More...
 
void operator= (const HelmholtzFGMRESMG &)=delete
 Broken assignment operator. More...
 
void set_preconditioner_LHS ()
 
void solve (Problem *const &problem_pt, DoubleVector &result)
 
- Public Member Functions inherited from oomph::HelmholtzGMRESMG< MATRIX >
 HelmholtzGMRESMG ()
 Constructor. More...
 
virtual ~HelmholtzGMRESMG ()
 Destructor (cleanup storage) More...
 
 HelmholtzGMRESMG (const HelmholtzGMRESMG &)=delete
 Broken copy constructor. More...
 
void operator= (const HelmholtzGMRESMG &)=delete
 Broken assignment operator. More...
 
void disable_resolve ()
 Overload disable resolve so that it cleans up memory too. More...
 
void preconditioner_solve (const DoubleVector &r, DoubleVector &z)
 
void setup ()
 
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...
 
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)
 
- Public Member Functions inherited from oomph::BlockPreconditioner< MATRIX >
 BlockPreconditioner ()
 Constructor. More...
 
virtual ~BlockPreconditioner ()
 Destructor. More...
 
 BlockPreconditioner (const BlockPreconditioner &)=delete
 Broken copy constructor. More...
 
void operator= (const BlockPreconditioner &)=delete
 Broken assignment operator. More...
 
MATRIX * matrix_pt () const
 
void turn_on_recursive_debug_flag ()
 
void turn_off_recursive_debug_flag ()
 
void turn_on_debug_flag ()
 Toggles on the debug flag. More...
 
void turn_off_debug_flag ()
 Toggles off the debug flag. More...
 
void turn_into_subsidiary_block_preconditioner (BlockPreconditioner< MATRIX > *master_block_prec_pt, const Vector< unsigned > &doftype_in_master_preconditioner_coarse)
 
void turn_into_subsidiary_block_preconditioner (BlockPreconditioner< MATRIX > *master_block_prec_pt, const Vector< unsigned > &doftype_in_master_preconditioner_coarse, const Vector< Vector< unsigned >> &doftype_coarsen_map_coarse)
 
virtual void block_setup ()
 
void block_setup (const Vector< unsigned > &dof_to_block_map)
 
void get_block (const unsigned &i, const unsigned &j, MATRIX &output_matrix, const bool &ignore_replacement_block=false) const
 
MATRIX get_block (const unsigned &i, const unsigned &j, const bool &ignore_replacement_block=false) const
 
void set_master_matrix_pt (MATRIX *in_matrix_pt)
 Set the matrix_pt in the upper-most master preconditioner. More...
 
void get_block_other_matrix (const unsigned &i, const unsigned &j, MATRIX *in_matrix_pt, MATRIX &output_matrix)
 
void get_blocks (DenseMatrix< bool > &required_blocks, DenseMatrix< MATRIX * > &block_matrix_pt) const
 
void get_dof_level_block (const unsigned &i, const unsigned &j, MATRIX &output_block, const bool &ignore_replacement_block=false) const
 
MATRIX get_concatenated_block (const VectorMatrix< BlockSelector > &selected_block)
 
void get_concatenated_block_vector (const Vector< unsigned > &block_vec_number, const DoubleVector &v, DoubleVector &b)
 
void return_concatenated_block_vector (const Vector< unsigned > &block_vec_number, const DoubleVector &b, DoubleVector &v) const
 Takes concatenated block ordered vector, b, and copies its. More...
 
void get_block_vectors (const Vector< unsigned > &block_vec_number, const DoubleVector &v, Vector< DoubleVector > &s) const
 
void get_block_vectors (const DoubleVector &v, Vector< DoubleVector > &s) const
 
void return_block_vectors (const Vector< unsigned > &block_vec_number, const Vector< DoubleVector > &s, DoubleVector &v) const
 
void return_block_vectors (const Vector< DoubleVector > &s, DoubleVector &v) const
 
void get_block_vector (const unsigned &n, const DoubleVector &v, DoubleVector &b) const
 
void return_block_vector (const unsigned &n, const DoubleVector &b, DoubleVector &v) const
 
void get_block_ordered_preconditioner_vector (const DoubleVector &v, DoubleVector &w)
 
void return_block_ordered_preconditioner_vector (const DoubleVector &w, DoubleVector &v) const
 
unsigned nblock_types () const
 Return the number of block types. More...
 
unsigned ndof_types () const
 Return the total number of DOF types. More...
 
const Meshmesh_pt (const unsigned &i) const
 
unsigned nmesh () const
 
int block_number (const unsigned &i_dof) const
 Return the block number corresponding to a global index i_dof. More...
 
int index_in_block (const unsigned &i_dof) const
 
const LinearAlgebraDistributionblock_distribution_pt (const unsigned &b) const
 Access function to the block distributions (const version). More...
 
LinearAlgebraDistributionblock_distribution_pt (const unsigned b)
 Access function to the block distributions (non-const version). More...
 
LinearAlgebraDistributiondof_block_distribution_pt (const unsigned &b)
 Access function to the dof-level block distributions. More...
 
const LinearAlgebraDistributionmaster_distribution_pt () const
 
unsigned ndof_types_in_mesh (const unsigned &i) const
 
bool is_subsidiary_block_preconditioner () const
 
bool is_master_block_preconditioner () const
 
void set_block_output_to_files (const std::string &basefilename)
 
void disable_block_output_to_files ()
 Turn off output of blocks (by clearing the basefilename string). More...
 
bool block_output_on () const
 Test if output of blocks is on or not. More...
 
void output_blocks_to_files (const std::string &basefilename, const unsigned &precision=8) const
 
void post_block_matrix_assembly_partial_clear ()
 
BlockPreconditioner< MATRIX > * master_block_preconditioner_pt () const
 Access function to the master block preconditioner pt. More...
 
void clear_block_preconditioner_base ()
 
void document ()
 
Vector< Vector< unsigned > > doftype_coarsen_map_fine () const
 
Vector< unsignedget_fine_grain_dof_types_in (const unsigned &i) const
 
unsigned nfine_grain_dof_types_in (const unsigned &i) const
 
MapMatrix< unsigned, CRDoubleMatrix * > replacement_dof_block_pt () const
 Access function to the replaced dof-level blocks. More...
 
void setup_matrix_vector_product (MatrixVectorProduct *matvec_prod_pt, CRDoubleMatrix *block_pt, const Vector< unsigned > &block_col_indices)
 
void setup_matrix_vector_product (MatrixVectorProduct *matvec_prod_pt, CRDoubleMatrix *block_pt, const unsigned &block_col_index)
 
void internal_get_block_ordered_preconditioner_vector (const DoubleVector &v, DoubleVector &w) const
 
void internal_return_block_ordered_preconditioner_vector (const DoubleVector &w, DoubleVector &v) const
 
unsigned internal_nblock_types () const
 
unsigned internal_ndof_types () const
 
void internal_return_block_vector (const unsigned &n, const DoubleVector &b, DoubleVector &v) const
 
void internal_get_block_vector (const unsigned &n, const DoubleVector &v, DoubleVector &b) const
 
void internal_get_block_vectors (const Vector< unsigned > &block_vec_number, const DoubleVector &v, Vector< DoubleVector > &s) const
 
void internal_get_block_vectors (const DoubleVector &v, Vector< DoubleVector > &s) const
 
void internal_return_block_vectors (const Vector< unsigned > &block_vec_number, const Vector< DoubleVector > &s, DoubleVector &v) const
 
void internal_return_block_vectors (const Vector< DoubleVector > &s, DoubleVector &v) const
 
void internal_get_block (const unsigned &i, const unsigned &j, MATRIX &output_block) const
 
int internal_block_number (const unsigned &i_dof) const
 
int internal_index_in_block (const unsigned &i_dof) const
 
const LinearAlgebraDistributioninternal_block_distribution_pt (const unsigned &b) const
 Access function to the internal block distributions. More...
 
void insert_auxiliary_block_distribution (const Vector< unsigned > &block_vec_number, LinearAlgebraDistribution *dist_pt)
 
void block_matrix_test (const unsigned &i, const unsigned &j, const MATRIX *block_matrix_pt) const
 
template<typename myType >
int get_index_of_value (const Vector< myType > &vec, const myType val, const bool sorted=false) const
 
void internal_get_block (const unsigned &block_i, const unsigned &block_j, CRDoubleMatrix &output_block) const
 
void get_dof_level_block (const unsigned &block_i, const unsigned &block_j, CRDoubleMatrix &output_block, const bool &ignore_replacement_block) const
 
- Public Member Functions inherited from oomph::Preconditioner
 Preconditioner ()
 Constructor. More...
 
 Preconditioner (const Preconditioner &)=delete
 Broken copy constructor. More...
 
void operator= (const Preconditioner &)=delete
 Broken assignment operator. More...
 
virtual ~Preconditioner ()
 Destructor (empty) More...
 
virtual void preconditioner_solve_transpose (const DoubleVector &r, DoubleVector &z)
 
void setup (DoubleMatrixBase *matrix_pt)
 
void setup (const Problem *problem_pt, DoubleMatrixBase *matrix_pt)
 
void enable_silent_preconditioner_setup ()
 Set up the block preconditioner quietly! More...
 
void disable_silent_preconditioner_setup ()
 Be verbose in the block preconditioner setup. More...
 
virtual void set_matrix_pt (DoubleMatrixBase *matrix_pt)
 Set the matrix pointer. More...
 
virtual const OomphCommunicatorcomm_pt () const
 Get function for comm pointer. More...
 
virtual void set_comm_pt (const OomphCommunicator *const comm_pt)
 Set the communicator pointer. More...
 
double setup_time () const
 Returns the time to setup the preconditioner. More...
 
virtual void turn_into_subsidiary_block_preconditioner (BlockPreconditioner< CRDoubleMatrix > *master_block_prec_pt, const Vector< unsigned > &doftype_in_master_preconditioner_coarse)
 
virtual void turn_into_subsidiary_block_preconditioner (BlockPreconditioner< CRDoubleMatrix > *master_block_prec_pt, const Vector< unsigned > &doftype_in_master_preconditioner_coarse, const Vector< Vector< unsigned >> &doftype_coarsen_map_coarse)
 

Private Member Functions

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< std::complex< double >>> &hessenberg, const Vector< std::complex< double >> &s, const Vector< Vector< DoubleVector >> &z_m, Vector< DoubleVector > &x)
 Helper function to update the result vector. More...
 

Additional Inherited Members

- Protected Member Functions inherited from oomph::HelmholtzGMRESMG< MATRIX >
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 complex_matrix_multiplication (Vector< CRDoubleMatrix * > const matrices_pt, const Vector< DoubleVector > &x, Vector< DoubleVector > &soln)
 
void update (const unsigned &k, const Vector< Vector< std::complex< double >>> &hessenberg, const Vector< std::complex< double >> &s, const Vector< Vector< DoubleVector >> &v, Vector< DoubleVector > &x)
 Helper function to update the result vector. More...
 
void generate_plane_rotation (std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
 
void apply_plane_rotation (std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
 
- Protected Member Functions inherited from oomph::DistributableLinearAlgebraObject
void clear_distribution ()
 
- Protected Member Functions inherited from oomph::BlockPreconditioner< MATRIX >
void set_nmesh (const unsigned &n)
 
void set_mesh (const unsigned &i, const Mesh *const mesh_pt, const bool &allow_multiple_element_type_in_mesh=false)
 
void set_replacement_dof_block (const unsigned &block_i, const unsigned &block_j, CRDoubleMatrix *replacement_dof_block_pt)
 
bool any_mesh_distributed () const
 
int internal_dof_number (const unsigned &i_dof) const
 
unsigned internal_index_in_dof (const unsigned &i_dof) const
 
unsigned internal_block_dimension (const unsigned &b) const
 
unsigned internal_dof_block_dimension (const unsigned &i) const
 
unsigned master_nrow () const
 
unsigned internal_master_dof_number (const unsigned &b) const
 
const LinearAlgebraDistributioninternal_preconditioner_matrix_distribution_pt () const
 
const LinearAlgebraDistributionpreconditioner_matrix_distribution_pt () const
 
- Protected Attributes inherited from oomph::HelmholtzGMRESMG< MATRIX >
unsigned Iterations
 Number of iterations taken. More...
 
Vector< CRDoubleMatrix * > Matrices_storage_pt
 Vector of pointers to the real and imaginary part of the system matrix. More...
 
bool Resolving
 
bool Matrix_can_be_deleted
 
bool Preconditioner_LHS
 
- 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
 
- Protected Attributes inherited from oomph::BlockPreconditioner< MATRIX >
MapMatrix< unsigned, CRDoubleMatrix * > Replacement_dof_block_pt
 The replacement dof-level blocks. More...
 
Vector< LinearAlgebraDistribution * > Block_distribution_pt
 The distribution for the blocks. More...
 
Vector< Vector< unsigned > > Block_to_dof_map_coarse
 
Vector< Vector< unsigned > > Block_to_dof_map_fine
 Mapping for the block types to the most fine grain dof types. More...
 
Vector< Vector< unsigned > > Doftype_coarsen_map_coarse
 
Vector< Vector< unsigned > > Doftype_coarsen_map_fine
 
Vector< LinearAlgebraDistribution * > Internal_block_distribution_pt
 Storage for the default distribution for each internal block. More...
 
Vector< LinearAlgebraDistribution * > Dof_block_distribution_pt
 
Vector< unsignedAllow_multiple_element_type_in_mesh
 
Vector< const Mesh * > Mesh_pt
 
Vector< unsignedNdof_types_in_mesh
 
unsigned Internal_nblock_types
 
unsigned Internal_ndof_types
 
- Protected Attributes inherited from oomph::Preconditioner
bool Silent_preconditioner_setup
 Boolean to indicate whether or not the build should be done silently. More...
 
std::ostream * Stream_pt
 Pointer to the output stream – defaults to std::cout. More...
 
- Static Protected Attributes inherited from oomph::IterativeLinearSolver
static IdentityPreconditioner Default_preconditioner
 

Detailed Description

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

//////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// The FGMRES method, i.e. the flexible variant of the GMRES method which allows for nonconstant preconditioners [see Saad Y, "Iterative methods for sparse linear systems", p.287]. Note, FGMRES can only cater to right preconditioning; if the user tries to switch to left preconditioning they will be notified of this

Constructor & Destructor Documentation

◆ HelmholtzFGMRESMG() [1/2]

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

Constructor (empty)

3244  : HelmholtzGMRESMG<MATRIX>()
3245  {
3246  // Can only use RHS preconditioning
3247  this->Preconditioner_LHS = false;
3248  };
bool Preconditioner_LHS
Definition: complex_smoother.h:2437

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

◆ ~HelmholtzFGMRESMG()

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

Destructor (cleanup storage)

3252  {
3253  // Call the clean up function in the base class GMRES
3254  this->clean_up_memory();
3255  }
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
Definition: complex_smoother.h:2053

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

◆ HelmholtzFGMRESMG() [2/2]

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

Broken copy constructor.

Member Function Documentation

◆ operator=()

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

Broken assignment operator.

◆ set_preconditioner_LHS()

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

Overloaded function to let the user know that left preconditioning is not possible with FGMRES, only right preconditioning

3266  {
3267  // Create an output stream
3268  std::ostringstream error_message_stream;
3269 
3270  // Create an error message
3271  error_message_stream << "FGMRES cannot use left preconditioning. It is "
3272  << "only capable of using right preconditioning."
3273  << std::endl;
3274 
3275  // Throw the error message
3276  throw OomphLibError(error_message_stream.str(),
3279  } // End of set_preconditioner_LHS
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ solve()

template<typename MATRIX >
void oomph::HelmholtzFGMRESMG< MATRIX >::solve ( Problem *const &  problem_pt,
DoubleVector result 
)
inlinevirtual

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.

Reimplemented from oomph::HelmholtzGMRESMG< MATRIX >.

3285  {
3286 #ifdef OOMPH_HAS_MPI
3287  // Make sure that this is running in serial. Can't guarantee it'll
3288  // work when the problem is distributed over several processors
3289  if (MPI_Helpers::communicator_pt()->nproc() > 1)
3290  {
3291  // Throw a warning
3292  OomphLibWarning("Can't guarantee the MG solver will work in parallel!",
3295  }
3296 #endif
3297 
3298  // Find # of degrees of freedom (variables)
3299  unsigned n_dof = problem_pt->ndof();
3300 
3301  // Initialise timer
3302  double t_start = TimingHelpers::timer();
3303 
3304  // We're not re-solving
3305  this->Resolving = false;
3306 
3307  // Get rid of any previously stored data
3308  this->clean_up_memory();
3309 
3310  // Grab the communicator from the MGProblem object and assign it
3311  this->set_comm_pt(problem_pt->communicator_pt());
3312 
3313  // Setup the distribution
3314  LinearAlgebraDistribution dist(
3315  problem_pt->communicator_pt(), n_dof, false);
3316 
3317  // Build the internal distribution in this way because both the
3318  // IterativeLinearSolver and BlockPreconditioner class have base-
3319  // class subobjects of type oomph::DistributableLinearAlgebraObject
3321 
3322  // Get Jacobian matrix in format specified by template parameter
3323  // and nonlinear residual vector
3324  MATRIX* matrix_pt = new MATRIX;
3325  DoubleVector f;
3326  if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt) != 0)
3327  {
3328  if (dynamic_cast<CRDoubleMatrix*>(matrix_pt) != 0)
3329  {
3330  dynamic_cast<CRDoubleMatrix*>(matrix_pt)->build(
3333  }
3334  }
3335 
3336  // Get the Jacobian and residuals vector
3337  problem_pt->get_jacobian(f, *matrix_pt);
3338 
3339  // We've made the matrix, we can delete it...
3340  this->Matrix_can_be_deleted = true;
3341 
3342  // Replace the current matrix used in Preconditioner by the new matrix
3343  this->set_matrix_pt(matrix_pt);
3344 
3345  // The preconditioner works with one mesh; set it! Since we only use
3346  // the block preconditioner on the finest level, we use the mesh from
3347  // that level
3348  this->set_nmesh(1);
3349 
3350  // Elements in actual pml layer are trivially wrapped versions of
3351  // their bulk counterparts. Technically they are different elements
3352  // so we have to allow different element types
3353  bool allow_different_element_types_in_mesh = true;
3354  this->set_mesh(
3355  0, problem_pt->mesh_pt(), allow_different_element_types_in_mesh);
3356 
3357  // Set up the generic block look up scheme
3358  this->block_setup();
3359 
3360  // Extract the number of blocks.
3361  unsigned nblock_types = this->nblock_types();
3362 
3363 #ifdef PARANOID
3364  // PARANOID check - there must only be two block types
3365  if (nblock_types != 2)
3366  {
3367  // Create the error message
3368  std::stringstream tmp;
3369  tmp << "There are supposed to be two block types.\nYours has "
3370  << nblock_types << std::endl;
3371 
3372  // Throw an error
3373  throw OomphLibError(
3375  }
3376 #endif
3377 
3378  // Resize the storage for the system matrices
3379  this->Matrices_storage_pt.resize(2, 0);
3380 
3381  // Loop over the rows of the block matrix
3382  for (unsigned i = 0; i < nblock_types; i++)
3383  {
3384  // Fix the column index
3385  unsigned j = 0;
3386 
3387  // Create new CRDoubleMatrix objects
3388  this->Matrices_storage_pt[i] = new CRDoubleMatrix;
3389 
3390  // Extract the required blocks, i.e. the first column
3391  this->get_block(i, j, *(this->Matrices_storage_pt[i]));
3392  }
3393 
3394  // Doc time for setup
3395  double t_end = TimingHelpers::timer();
3396  this->Jacobian_setup_time = t_end - t_start;
3397 
3398  if (this->Doc_time)
3399  {
3400  oomph_info << "\nTime for setup of block Jacobian [sec]: "
3401  << this->Jacobian_setup_time << std::endl;
3402  }
3403 
3404  // Call linear algebra-style solver
3405  // If the result distribution is wrong, then redistribute
3406  // before the solve and return to original distribution
3407  // afterwards
3408  if ((!(*result.distribution_pt() ==
3410  (result.built()))
3411  {
3412  // Make a distribution object
3413  LinearAlgebraDistribution temp_global_dist(result.distribution_pt());
3414 
3415  // Build the result vector distribution
3416  result.build(IterativeLinearSolver::distribution_pt(), 0.0);
3417 
3418  // Solve the problem
3419  solve_helper(matrix_pt, f, result);
3420 
3421  // Redistribute the vector
3422  result.redistribute(&temp_global_dist);
3423  }
3424  // Otherwise just solve
3425  else
3426  {
3427  // Solve
3428  solve_helper(matrix_pt, f, result);
3429  }
3430 
3431  // Kill matrix unless it's still required for resolve
3432  if (!(this->Enable_resolve))
3433  {
3434  // Clean up anything left in memory
3435  this->clean_up_memory();
3436  }
3437  } // End of solve
int i
Definition: BiCGSTAB_step_by_step.cpp:9
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
void get_block(const unsigned &i, const unsigned &j, MATRIX &output_matrix, const bool &ignore_replacement_block=false) const
Definition: block_preconditioner.h:673
unsigned nblock_types() const
Return the number of block types.
Definition: block_preconditioner.h:1670
MATRIX * matrix_pt() const
Definition: block_preconditioner.h:520
void set_nmesh(const unsigned &n)
Definition: block_preconditioner.h:2851
virtual void block_setup()
Definition: block_preconditioner.cc:2483
void set_mesh(const unsigned &i, const Mesh *const mesh_pt, const bool &allow_multiple_element_type_in_mesh=false)
Definition: block_preconditioner.h:2866
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
Definition: linear_algebra_distribution.h:457
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
Definition: linear_algebra_distribution.h:507
DistributableLinearAlgebraObject()
Default constructor - create a distribution.
Definition: linear_algebra_distribution.h:438
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
Definition: complex_smoother.h:3551
bool Matrix_can_be_deleted
Definition: complex_smoother.h:2433
Vector< CRDoubleMatrix * > Matrices_storage_pt
Vector of pointers to the real and imaginary part of the system matrix.
Definition: complex_smoother.h:2425
bool Resolving
Definition: complex_smoother.h:2429
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 Enable_resolve
Definition: linear_solver.h:73
static OomphCommunicator * communicator_pt()
access to the global oomph-lib communicator
Definition: oomph_utilities.cc:1046
virtual void set_comm_pt(const OomphCommunicator *const comm_pt)
Set the communicator pointer.
Definition: preconditioner.h:193
virtual void set_matrix_pt(DoubleMatrixBase *matrix_pt)
Set the matrix pointer.
Definition: preconditioner.h:165
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
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
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References oomph::BlockPreconditioner< MATRIX >::block_setup(), oomph::DoubleVector::build(), oomph::DistributableLinearAlgebraObject::build_distribution(), oomph::DoubleVector::built(), oomph::HelmholtzGMRESMG< MATRIX >::clean_up_memory(), oomph::MPI_Helpers::communicator_pt(), oomph::Problem::communicator_pt(), oomph::DistributableLinearAlgebraObject::distribution_pt(), oomph::LinearSolver::Doc_time, oomph::LinearSolver::Enable_resolve, f(), oomph::BlockPreconditioner< MATRIX >::get_block(), oomph::Problem::get_jacobian(), i, j, oomph::IterativeLinearSolver::Jacobian_setup_time, oomph::HelmholtzGMRESMG< MATRIX >::Matrices_storage_pt, oomph::HelmholtzGMRESMG< MATRIX >::Matrix_can_be_deleted, oomph::BlockPreconditioner< MATRIX >::matrix_pt(), oomph::Problem::mesh_pt(), oomph::BlockPreconditioner< MATRIX >::nblock_types(), oomph::Problem::ndof(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::DoubleVector::redistribute(), oomph::HelmholtzGMRESMG< MATRIX >::Resolving, oomph::Preconditioner::set_comm_pt(), oomph::Preconditioner::set_matrix_pt(), oomph::BlockPreconditioner< MATRIX >::set_mesh(), oomph::BlockPreconditioner< MATRIX >::set_nmesh(), oomph::HelmholtzFGMRESMG< MATRIX >::solve_helper(), oomph::TimingHelpers::timer(), and tmp.

◆ solve_helper()

template<typename MATRIX >
void oomph::HelmholtzFGMRESMG< 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++/

3555  {
3556  // Set the number of dof types (real and imaginary for this solver)
3557  unsigned n_dof_types = this->ndof_types();
3558 
3559 #ifdef PARANOID
3560  // This only works for 2 dof types
3561  if (n_dof_types != 2)
3562  {
3563  // Create an output stream
3564  std::stringstream error_message_stream;
3565 
3566  // Create the error message
3567  error_message_stream << "This preconditioner only works for problems "
3568  << "with 2 dof types\nYours has " << n_dof_types;
3569 
3570  // Throw the error message
3571  throw OomphLibError(error_message_stream.str(),
3574  }
3575 #endif
3576 
3577  // Get the number of dofs (note, the total number of dofs in the problem
3578  // is 2*n_row but if the constituent vectors and matrices were stored in
3579  // complex objects there would only be (n_row) rows so we use that)
3580  unsigned n_row = this->Matrices_storage_pt[0]->nrow();
3581 
3582  // Make sure Max_iter isn't greater than n_dof. The user cannot use this
3583  // many iterations when using Krylov subspace methods
3584  if (this->Max_iter > n_row)
3585  {
3586  // Create an output string stream
3587  std::ostringstream error_message_stream;
3588 
3589  // Create the error message
3590  error_message_stream << "The maximum number of iterations cannot exceed "
3591  << "the number of rows in the problem."
3592  << "\nMaximum number of iterations: "
3593  << this->Max_iter << "\nNumber of rows: " << n_row
3594  << std::endl;
3595 
3596  // Throw the error message
3597  throw OomphLibError(error_message_stream.str(),
3600  }
3601 
3602 #ifdef PARANOID
3603  // Loop over the real and imaginary parts
3604  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3605  {
3606  // PARANOID check that if the matrix is distributable then it should not
3607  // be then it should not be distributed
3608  if (dynamic_cast<DistributableLinearAlgebraObject*>(
3609  this->Matrices_storage_pt[dof_type]) != 0)
3610  {
3611  if (dynamic_cast<DistributableLinearAlgebraObject*>(
3612  this->Matrices_storage_pt[dof_type])
3613  ->distributed())
3614  {
3615  std::ostringstream error_message_stream;
3616  error_message_stream << "The matrix must not be distributed.";
3617  throw OomphLibError(error_message_stream.str(),
3620  }
3621  }
3622  }
3623  // PARANOID check that this rhs distribution is setup
3624  if (!rhs.built())
3625  {
3626  std::ostringstream error_message_stream;
3627  error_message_stream << "The rhs vector distribution must be setup.";
3628  throw OomphLibError(error_message_stream.str(),
3631  }
3632  // PARANOID check that the rhs has the right number of global rows
3633  if (rhs.nrow() != 2 * n_row)
3634  {
3635  std::ostringstream error_message_stream;
3636  error_message_stream << "RHS does not have the same dimension as the"
3637  << " linear system";
3638  throw OomphLibError(error_message_stream.str(),
3641  }
3642  // PARANOID check that the rhs is not distributed
3643  if (rhs.distribution_pt()->distributed())
3644  {
3645  std::ostringstream error_message_stream;
3646  error_message_stream << "The rhs vector must not be distributed.";
3647  throw OomphLibError(error_message_stream.str(),
3650  }
3651  // PARANOID check that if the result is setup it matches the distribution
3652  // of the rhs
3653  if (solution.built())
3654  {
3655  if (!(*rhs.distribution_pt() == *solution.distribution_pt()))
3656  {
3657  std::ostringstream error_message_stream;
3658  error_message_stream << "If the result distribution is setup then it "
3659  << "must be the same as the rhs distribution";
3660  throw OomphLibError(error_message_stream.str(),
3663  }
3664  } // if (solution[dof_type].built())
3665 #endif
3666 
3667  // Set up the solution distribution if it's not already distributed
3668  if (!solution.built())
3669  {
3670  // Build the distribution
3672  }
3673  // Otherwise initialise all entries to zero
3674  else
3675  {
3676  // Initialise the entries in the k-th vector in solution to zero
3677  solution.initialise(0.0);
3678  }
3679 
3680  // Create a vector of DoubleVectors (this is a distributed vector so we have
3681  // to create two separate DoubleVector objects to cope with the arithmetic)
3682  Vector<DoubleVector> block_solution(n_dof_types);
3683 
3684  // Create a vector of DoubleVectors (this is a distributed vector so we have
3685  // to create two separate DoubleVector objects to cope with the arithmetic)
3686  Vector<DoubleVector> block_rhs(n_dof_types);
3687 
3688  // Build the distribution of both vectors
3689  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3690  {
3691  // Build the distribution of the k-th constituent vector
3692  block_solution[dof_type].build(this->block_distribution_pt(dof_type),
3693  0.0);
3694 
3695  // Build the distribution of the k-th constituent vector
3696  block_rhs[dof_type].build(this->block_distribution_pt(dof_type), 0.0);
3697  }
3698 
3699  // Grab the solution vector in block form
3700  this->get_block_vectors(solution, block_solution);
3701 
3702  // Grab the RHS vector in block form
3703  this->get_block_vectors(rhs, block_rhs);
3704 
3705  // Start the solver timer
3706  double t_start = TimingHelpers::timer();
3707 
3708  // Storage for the relative residual
3709  double resid;
3710 
3711  // Initialise vectors (since these are not distributed vectors we template
3712  // one vector by the type std::complex<double> instead of using two vectors,
3713  // each templated by the type double
3714 
3715  // Vector, s, used in the minimisation problem: J(y)=min||s-R_m*y||
3716  // [see Saad Y."Iterative methods for sparse linear systems", p.176.]
3717  Vector<std::complex<double>> s(n_row + 1, std::complex<double>(0.0, 0.0));
3718 
3719  // Vector to store the value of cos(theta) when using the Givens rotation
3720  Vector<std::complex<double>> cs(n_row + 1, std::complex<double>(0.0, 0.0));
3721 
3722  // Vector to store the value of sin(theta) when using the Givens rotation
3723  Vector<std::complex<double>> sn(n_row + 1, std::complex<double>(0.0, 0.0));
3724 
3725  // Create a vector of DoubleVectors (this is a distributed vector so we have
3726  // to create two separate DoubleVector objects to cope with the arithmetic)
3727  Vector<DoubleVector> block_w(n_dof_types);
3728 
3729  // Build the distribution of both vectors
3730  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3731  {
3732  // Build the distribution of the k-th constituent vector
3733  block_w[dof_type].build(this->block_distribution_pt(dof_type), 0.0);
3734  }
3735 
3736  // Set up the preconditioner only if we're not re-solving
3737  if (!(this->Resolving))
3738  {
3739  // Only set up the preconditioner before solve if required
3741  {
3742  // Set up the preconditioner from the Jacobian matrix
3743  double t_start_prec = TimingHelpers::timer();
3744 
3745  // Use the setup function in the Preconditioner class
3746  this->preconditioner_pt()->setup(dynamic_cast<MATRIX*>(matrix_pt));
3747 
3748  // Doc time for setup of preconditioner
3749  double t_end_prec = TimingHelpers::timer();
3750  this->Preconditioner_setup_time = t_end_prec - t_start_prec;
3751 
3752  // If time documentation is enabled
3753  if (this->Doc_time)
3754  {
3755  // Output the time taken
3756  oomph_info << "Time for setup of preconditioner [sec]: "
3757  << this->Preconditioner_setup_time << std::endl;
3758  }
3759  }
3760  }
3761  else
3762  {
3763  // If time documentation is enabled
3764  if (this->Doc_time)
3765  {
3766  // Notify the user
3767  oomph_info << "Setup of preconditioner is bypassed in resolve mode"
3768  << std::endl;
3769  }
3770  } // if (!Resolving) else
3771 
3772  // Create a vector of DoubleVectors to store the RHS of b-Jx=Mr. We assume
3773  // both x=0 and that a preconditioner is not applied by which we deduce b=r
3774  Vector<DoubleVector> block_r(n_dof_types);
3775 
3776  // Build the distribution of both vectors
3777  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3778  {
3779  // Build the distribution of the k-th constituent vector
3780  block_r[dof_type].build(this->block_distribution_pt(dof_type), 0.0);
3781  }
3782 
3783  // Store the value of b (the RHS vector) in r
3784  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3785  {
3786  // Copy the entries of rhs into r
3787  block_r[dof_type] = block_rhs[dof_type];
3788  }
3789 
3790  // Calculate the norm of the real part of r
3791  double norm_r = block_r[0].norm();
3792 
3793  // Calculate the norm of the imaginary part of r
3794  double norm_c = block_r[1].norm();
3795 
3796  // Compute norm(r)
3797  double normb = sqrt(pow(norm_r, 2.0) + pow(norm_c, 2.0));
3798 
3799  // Set the value of beta (the initial residual)
3800  double beta = normb;
3801 
3802  // Compute the initial relative residual. If the entries of the RHS vector
3803  // are all zero then set normb equal to one. This is because we divide the
3804  // value of the norm at later stages by normb and dividing by zero is not
3805  // definied
3806  if (normb == 0.0)
3807  {
3808  // Set the value of normb
3809  normb = 1.0;
3810  }
3811 
3812  // Calculate the ratio between the initial norm and the current norm.
3813  // Since we haven't completed an iteration yet this will simply be one
3814  // unless normb was zero, in which case resid will have value zero
3815  resid = beta / normb;
3816 
3817  // If required, will document convergence history to screen or file (if
3818  // stream open)
3819  if (this->Doc_convergence_history)
3820  {
3821  // If an output file which is open isn't provided then output to screen
3822  if (!(this->Output_file_stream.is_open()))
3823  {
3824  // Output the residual value to the screen
3825  oomph_info << 0 << " " << resid << std::endl;
3826  }
3827  // Otherwise, output to file
3828  else
3829  {
3830  // Output the residual value to file
3831  this->Output_file_stream << 0 << " " << resid << std::endl;
3832  }
3833  } // if (Doc_convergence_history)
3834 
3835  // If the GMRES algorithm converges immediately
3836  if (resid <= this->Tolerance)
3837  {
3838  // If time documentation is enabled
3839  if (this->Doc_time)
3840  {
3841  // Notify the user
3842  oomph_info << "FGMRES converged immediately. Normalised residual norm: "
3843  << resid << std::endl;
3844  }
3845 
3846  // Finish running the solver
3847  return;
3848  } // if (resid<=Tolerance)
3849 
3850  // Initialise a vector of orthogonal basis vectors
3851  Vector<Vector<DoubleVector>> block_v;
3852 
3853  // Resize the number of vectors needed
3854  block_v.resize(n_row + 1);
3855 
3856  // Create a vector of DoubleVectors (stores the preconditioned vectors)
3857  Vector<Vector<DoubleVector>> block_z;
3858 
3859  // Resize the number of vectors needed
3860  block_z.resize(n_row + 1);
3861 
3862  // Resize each Vector of DoubleVectors to store the real and imaginary
3863  // part of a given vector
3864  for (unsigned i = 0; i < n_row + 1; i++)
3865  {
3866  // Create space for two DoubleVector objects in each Vector
3867  block_v[i].resize(n_dof_types);
3868 
3869  // Create space for two DoubleVector objects in each Vector
3870  block_z[i].resize(n_dof_types);
3871  }
3872 
3873  // Initialise the upper hessenberg matrix. Since we are not using
3874  // distributed vectors here, the algebra is best done using entries
3875  // of the type std::complex<double>. NOTE: For implementation purposes
3876  // the upper Hessenberg matrix indices are swapped so the matrix is
3877  // effectively transposed
3878  Vector<Vector<std::complex<double>>> hessenberg(n_row + 1);
3879 
3880  // Build the zeroth basis vector
3881  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3882  {
3883  // Build the k-th part of the zeroth vector. Here k=0 and k=1 correspond
3884  // to the real and imaginary part of the zeroth vector, respectively
3885  block_v[0][dof_type].build(this->block_distribution_pt(dof_type), 0.0);
3886  }
3887 
3888  // Loop over the real and imaginary parts of v
3889  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3890  {
3891  // For fast access
3892  double* block_v0_pt = block_v[0][dof_type].values_pt();
3893 
3894  // For fast access
3895  const double* block_r_pt = block_r[dof_type].values_pt();
3896 
3897  // Set the zeroth basis vector v[0] to r/beta
3898  for (unsigned i = 0; i < n_row; i++)
3899  {
3900  // Assign the i-th entry of the zeroth basis vector
3901  block_v0_pt[i] = block_r_pt[i] / beta;
3902  }
3903  } // for (unsigned k=0;k<n_dof_types;k++)
3904 
3905  // Set the first entry in the minimisation problem RHS vector (is meant
3906  // to the vector beta*e_1 initially, where e_1 is the unit vector with
3907  // one in its first entry)
3908  s[0] = beta;
3909 
3910  // Compute the next step of the iterative scheme
3911  for (unsigned j = 0; j < this->Max_iter; j++)
3912  {
3913  // Resize the next column of the upper hessenberg matrix
3914  hessenberg[j].resize(j + 2, std::complex<double>(0.0, 0.0));
3915 
3916  // Calculate w_j=Jz_j where z_j=M^{-1}v_j (RHS prec.)
3917  {
3918  // Create a temporary vector
3920 
3921  // Create a temporary vector
3923 
3924  // Create a temporary vector
3926 
3927  // Create two DoubleVectors
3928  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
3929  {
3930  // Build the k-th part of the j-th preconditioning result vector
3931  block_z[j][dof_type].build(this->block_distribution_pt(dof_type),
3932  0.0);
3933  }
3934 
3935  // Copy the real and imaginary part of v[j] into one vector, vj
3936  this->return_block_vectors(block_v[j], vj);
3937 
3938  // Calculate z_j=M^{-1}v_j by saad p270
3939  this->preconditioner_pt()->preconditioner_solve(vj, zj);
3940 
3941  // Copy zj into z[j][0] and z[j][1]
3942  this->get_block_vectors(zj, block_z[j]);
3943 
3944  // Calculate w_j=J*(M^{-1}v_j). Note, we cannot use inbuilt complex
3945  // matrix algebra here as we're using distributed vectors
3947  this->Matrices_storage_pt, block_z[j], block_w);
3948  } // Calculate w=JM^{-1}v (RHS prec.)
3949 
3950  // For fast access
3951  double* block_w_r_pt = block_w[0].values_pt();
3952 
3953  // For fast access
3954  double* block_w_c_pt = block_w[1].values_pt();
3955 
3956  // Loop over all of the entries on and above the principal subdiagonal of
3957  // the Hessenberg matrix in the j-th column (remembering that
3958  // the indices of the upper Hessenberg matrix are swapped for the purpose
3959  // of implementation)
3960  for (unsigned i = 0; i < j + 1; i++)
3961  {
3962  // For fast access
3963  const double* block_vi_r_pt = block_v[i][0].values_pt();
3964 
3965  // For fast access
3966  const double* block_vi_c_pt = block_v[i][1].values_pt();
3967 
3968  // Loop over the entries of v and w
3969  for (unsigned k = 0; k < n_row; k++)
3970  {
3971  // Store the appropriate entry in v as a complex value
3972  std::complex<double> complex_v(block_vi_r_pt[k], block_vi_c_pt[k]);
3973 
3974  // Store the appropriate entry in w as a complex value
3975  std::complex<double> complex_w(block_w_r_pt[k], block_w_c_pt[k]);
3976 
3977  // Update the value of H(i,j) noting we're computing a complex
3978  // inner product here (the ordering is very important here!)
3979  hessenberg[j][i] += std::conj(complex_v) * complex_w;
3980  }
3981 
3982  // Orthonormalise w against all previous orthogonal vectors, v_i by
3983  // looping over its entries and updating them
3984  for (unsigned k = 0; k < n_row; k++)
3985  {
3986  // Update the real part of the k-th entry of w
3987  block_w_r_pt[k] -= (hessenberg[j][i].real() * block_vi_r_pt[k] -
3988  hessenberg[j][i].imag() * block_vi_c_pt[k]);
3989 
3990  // Update the imaginary part of the k-th entry of w
3991  block_w_c_pt[k] -= (hessenberg[j][i].real() * block_vi_c_pt[k] +
3992  hessenberg[j][i].imag() * block_vi_r_pt[k]);
3993  }
3994  } // for (unsigned i=0;i<j+1;i++)
3995 
3996  // Calculate the norm of the real part of w
3997  norm_r = block_w[0].norm();
3998 
3999  // Calculate the norm of the imaginary part of w
4000  norm_c = block_w[1].norm();
4001 
4002  // Calculate the norm of the vector w using norm_r and norm_c and assign
4003  // its value to the appropriate entry in the Hessenberg matrix
4004  hessenberg[j][j + 1] = sqrt(pow(norm_r, 2.0) + pow(norm_c, 2.0));
4005 
4006  // Build the (j+1)-th basis vector
4007  for (unsigned dof_type = 0; dof_type < n_dof_types; dof_type++)
4008  {
4009  // Build the k-th part of the zeroth vector. Here k=0 and k=1 correspond
4010  // to the real and imaginary part of the zeroth vector, respectively
4011  block_v[j + 1][dof_type].build(this->block_distribution_pt(dof_type),
4012  0.0);
4013  }
4014 
4015  // Check if the value of hessenberg[j][j+1] is zero. If it
4016  // isn't then we update the next entries in v
4017  if (hessenberg[j][j + 1] != 0.0)
4018  {
4019  // For fast access
4020  double* block_v_r_pt = block_v[j + 1][0].values_pt();
4021 
4022  // For fast access
4023  double* block_v_c_pt = block_v[j + 1][1].values_pt();
4024 
4025  // For fast access
4026  const double* block_w_r_pt = block_w[0].values_pt();
4027 
4028  // For fast access
4029  const double* block_w_c_pt = block_w[1].values_pt();
4030 
4031  // Notice, the value of H(j,j+1), as calculated above, is clearly a real
4032  // number. As such, calculating the division
4033  // v_{j+1}=w_{j}/h_{j+1,j},
4034  // here is simple, i.e. we don't need to worry about cross terms in the
4035  // algebra. To avoid computing h_{j+1,j} several times we precompute it
4036  double h_subdiag_val = hessenberg[j][j + 1].real();
4037 
4038  // Loop over the entries of the new orthogonal vector and set its values
4039  for (unsigned k = 0; k < n_row; k++)
4040  {
4041  // The i-th entry of the real component is given by
4042  block_v_r_pt[k] = block_w_r_pt[k] / h_subdiag_val;
4043 
4044  // Similarly, the i-th entry of the imaginary component is given by
4045  block_v_c_pt[k] = block_w_c_pt[k] / h_subdiag_val;
4046  }
4047  }
4048  // Otherwise, we have to jump to the next part of the algorithm; if
4049  // the value of hessenberg[j][j+1] is zero then the norm of the latest
4050  // orthogonal vector is zero. This is only possible if the entries
4051  // in w are all zero. As a result, the Krylov space of A and r_0 has
4052  // been spanned by the previously calculated orthogonal vectors
4053  else
4054  {
4055  // Book says "Set m=j and jump to step 11" (p.172)...
4056  // Do something here!
4057  oomph_info << "Subdiagonal Hessenberg entry is zero. "
4058  << "Do something here..." << std::endl;
4059  } // if (hessenberg[j][j+1]!=0.0)
4060 
4061  // Loop over the entries in the Hessenberg matrix and calculate the
4062  // entries of the Givens rotation matrices
4063  for (unsigned k = 0; k < j; k++)
4064  {
4065  // Apply the plane rotation to all of the previous entries in the
4066  // (j)-th column (remembering the indexing is reversed)
4067  this->apply_plane_rotation(
4068  hessenberg[j][k], hessenberg[j][k + 1], cs[k], sn[k]);
4069  }
4070 
4071  // Now calculate the entries of the latest Givens rotation matrix
4073  hessenberg[j][j], hessenberg[j][j + 1], cs[j], sn[j]);
4074 
4075  // Apply the plane rotation using the newly calculated entries
4076  this->apply_plane_rotation(
4077  hessenberg[j][j], hessenberg[j][j + 1], cs[j], sn[j]);
4078 
4079  // Apply a plane rotation to the corresponding entry in the vector
4080  // s used in the minimisation problem, J(y)=min||s-R_m*y||
4081  this->apply_plane_rotation(s[j], s[j + 1], cs[j], sn[j]);
4082 
4083  // Compute current residual using equation (6.42) in Saad Y, "Iterative
4084  // methods for sparse linear systems", p.177.]. Note, since s has complex
4085  // entries we have to use std::abs instead of std::fabs
4086  beta = std::abs(s[j + 1]);
4087 
4088  // Compute the relative residual
4089  resid = beta / normb;
4090 
4091  // If required will document convergence history to screen or file (if
4092  // stream open)
4093  if (this->Doc_convergence_history)
4094  {
4095  // If an output file which is open isn't provided then output to screen
4096  if (!(this->Output_file_stream.is_open()))
4097  {
4098  // Output the residual value to the screen
4099  oomph_info << j + 1 << " " << resid << std::endl;
4100  }
4101  // Otherwise, output to file
4102  else
4103  {
4104  // Output the residual value to file
4105  this->Output_file_stream << j + 1 << " " << resid << std::endl;
4106  }
4107  } // if (Doc_convergence_history)
4108 
4109  // If the required tolerance has been met
4110  if (resid < this->Tolerance)
4111  {
4112  // Store the number of iterations taken
4113  this->Iterations = j + 1;
4114 
4115  // Update the result vector using the result, x=x_0+V_m*y (where V_m
4116  // is given by v here)
4117  update(j, hessenberg, s, block_z, block_solution);
4118 
4119  // Copy the vectors in block_solution to solution
4120  this->return_block_vectors(block_solution, solution);
4121 
4122  // If time documentation was enabled
4123  if (this->Doc_time)
4124  {
4125  // Output the current normalised residual norm
4126  oomph_info << "\nFGMRES converged (1). Normalised residual norm: "
4127  << resid << std::endl;
4128 
4129  // Output the number of iterations it took for convergence
4130  oomph_info << "Number of iterations to convergence: " << j + 1 << "\n"
4131  << std::endl;
4132  }
4133 
4134  // Stop the timer
4135  double t_end = TimingHelpers::timer();
4136 
4137  // Calculate the time taken to calculate the solution
4138  this->Solution_time = t_end - t_start;
4139 
4140  // If time documentation was enabled
4141  if (this->Doc_time)
4142  {
4143  // Output the time taken to solve the problem using GMRES
4144  oomph_info << "Time for solve with FGMRES [sec]: "
4145  << this->Solution_time << std::endl;
4146  }
4147 
4148  // As we've met the tolerance for the solver and everything that should
4149  // be documented, has been, finish using the solver
4150  return;
4151  } // if (resid<Tolerance)
4152  } // for (unsigned j=0;j<Max_iter;j++)
4153 
4154  // Store the number of iterations taken
4155  this->Iterations = this->Max_iter;
4156 
4157  // Only update if we actually did something
4158  if (this->Max_iter > 0)
4159  {
4160  // Update the result vector using the result, x=x_0+V_m*y (where V_m
4161  // is given by v here)
4162  update(this->Max_iter - 1, hessenberg, s, block_z, block_solution);
4163 
4164  // Copy the vectors in block_solution to solution
4165  this->return_block_vectors(block_solution, solution);
4166  }
4167 
4168  // Compute the current residual
4169  beta = 0.0;
4170 
4171  // Get access to the values pointer (real)
4172  norm_r = block_r[0].norm();
4173 
4174  // Get access to the values pointer (imaginary)
4175  norm_c = block_r[1].norm();
4176 
4177  // Calculate the full norm
4178  beta = sqrt(pow(norm_r, 2.0) + pow(norm_c, 2.0));
4179 
4180  // Calculate the relative residual
4181  resid = beta / normb;
4182 
4183  // If the relative residual lies within tolerance
4184  if (resid < this->Tolerance)
4185  {
4186  // If time documentation is enabled
4187  if (this->Doc_time)
4188  {
4189  // Notify the user
4190  oomph_info << "\nFGMRES converged (2). Normalised residual norm: "
4191  << resid << "\nNumber of iterations to convergence: "
4192  << this->Iterations << "\n"
4193  << std::endl;
4194  }
4195 
4196  // End the timer
4197  double t_end = TimingHelpers::timer();
4198 
4199  // Calculate the time taken for the solver
4200  this->Solution_time = t_end - t_start;
4201 
4202  // If time documentation is enabled
4203  if (this->Doc_time)
4204  {
4205  oomph_info << "Time for solve with FGMRES [sec]: "
4206  << this->Solution_time << std::endl;
4207  }
4208  return;
4209  }
4210 
4211  // Otherwise GMRES failed convergence
4212  oomph_info << "\nFGMRES did not converge to required tolerance! "
4213  << "\nReturning with normalised residual norm: " << resid
4214  << "\nafter " << this->Max_iter << " iterations.\n"
4215  << std::endl;
4216 
4217  // Throw an error if requested
4218  if (this->Throw_error_after_max_iter)
4219  {
4220  std::string err = "Solver failed to converge and you requested an error";
4221  err += " on convergence failures.";
4222  throw OomphLibError(
4224  }
4225 
4226  // Finish using the solver
4227  return;
4228  } // End of solve_helper
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
AnnoyingScalar conj(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:133
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
RowVector3d w
Definition: Matrix_resize_int.cpp:3
void return_block_vectors(const Vector< unsigned > &block_vec_number, const Vector< DoubleVector > &s, DoubleVector &v) const
Definition: block_preconditioner.cc:3443
const LinearAlgebraDistribution * block_distribution_pt(const unsigned &b) const
Access function to the block distributions (const version).
Definition: block_preconditioner.h:1903
unsigned ndof_types() const
Return the total number of DOF types.
Definition: block_preconditioner.h:1694
void get_block_vectors(const Vector< unsigned > &block_vec_number, const DoubleVector &v, Vector< DoubleVector > &s) const
Definition: block_preconditioner.cc:2939
bool distributed() const
distribution is serial or distributed
Definition: linear_algebra_distribution.h:493
void update(const unsigned &k, const Vector< Vector< std::complex< double >>> &hessenberg, const Vector< std::complex< double >> &s, const Vector< Vector< DoubleVector >> &z_m, Vector< DoubleVector > &x)
Helper function to update the result vector.
Definition: complex_smoother.h:3446
void apply_plane_rotation(std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
Definition: complex_smoother.h:2406
void complex_matrix_multiplication(Vector< CRDoubleMatrix * > const matrices_pt, const Vector< DoubleVector > &x, Vector< DoubleVector > &soln)
Definition: complex_smoother.h:2086
unsigned Iterations
Number of iterations taken.
Definition: complex_smoother.h:2422
void generate_plane_rotation(std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
Definition: complex_smoother.h:2327
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
void hessenberg(int size=Size)
Definition: hessenberg.cpp:15
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
void solution(const Vector< double > &x, Vector< double > &u)
Definition: two_d_biharmonic.cc:113
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286

References abs(), beta, oomph::DoubleVector::built(), conj(), oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), hessenberg(), i, Global_Variables::Iterations, j, k, oomph::BlackBoxFDNewtonSolver::Max_iter, oomph::DistributableLinearAlgebraObject::nrow(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, Eigen::bfloat16_impl::pow(), s, BiharmonicTestFunctions1::solution(), sqrt(), oomph::Global_string_for_annotation::string(), oomph::TimingHelpers::timer(), and w.

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

◆ update()

template<typename MATRIX >
void oomph::HelmholtzFGMRESMG< MATRIX >::update ( const unsigned k,
const Vector< Vector< std::complex< double >>> &  hessenberg,
const Vector< std::complex< double >> &  s,
const Vector< Vector< DoubleVector >> &  z_m,
Vector< DoubleVector > &  x 
)
inlineprivate

Helper function to update the result vector.

3451  {
3452  // Make a local copy of s
3453  Vector<std::complex<double>> y(s);
3454 
3455  //-----------------------------------------------------------------
3456  // The Hessenberg matrix should be an upper triangular matrix at
3457  // this point (although from its storage it would appear to be a
3458  // lower triangular matrix since the indexing has been reversed)
3459  // so finding the minimiser of J(y)=min||s-R_m*y|| where R_m is
3460  // the matrix R in the QR factorisation of the Hessenberg matrix.
3461  // Therefore, to obtain y we simply need to use a backwards
3462  // substitution. Note: The implementation here may appear to be
3463  // somewhat confusing as the indexing in the Hessenberg matrix is
3464  // reversed. This implementation of a backwards substitution does
3465  // not run along the columns of the triangular matrix but rather
3466  // up the rows.
3467  //-----------------------------------------------------------------
3468 
3469  // The outer loop is a loop over the columns of the Hessenberg matrix
3470  // since the indexing is reversed
3471  for (int i = int(k); i >= 0; i--)
3472  {
3473  // Divide the i-th entry of y by the i-th diagonal entry of H
3474  y[i] /= hessenberg[i][i];
3475 
3476  // The inner loop is a loop over the rows of the Hessenberg matrix
3477  for (int j = i - 1; j >= 0; j--)
3478  {
3479  // Update the j-th entry of y
3480  y[j] -= hessenberg[i][j] * y[i];
3481  }
3482  } // for (int i=int(k);i>=0;i--)
3483 
3484  // Calculate the number of entries in x (simply use the real part as
3485  // both the real and imaginary part should have the same length)
3486  unsigned n_row = x[0].nrow();
3487 
3488  // Build a temporary vector with entries initialised to 0.0
3489  Vector<DoubleVector> block_update(2);
3490 
3491  // Build the distributions
3492  for (unsigned dof_type = 0; dof_type < 2; dof_type++)
3493  {
3494  // Build the (dof_type)-th vector of block_update
3495  block_update[dof_type].build(x[0].distribution_pt(), 0.0);
3496  }
3497 
3498  // Get access to the underlying values
3499  double* block_update_r_pt = block_update[0].values_pt();
3500 
3501  // Get access to the underlying values
3502  double* block_update_c_pt = block_update[1].values_pt();
3503 
3504  // Calculate x=Vy
3505  for (unsigned j = 0; j <= k; j++)
3506  {
3507  // Get access to j-th column of Z_m
3508  const double* z_mj_r_pt = z_m[j][0].values_pt();
3509 
3510  // Get access to j-th column of Z_m
3511  const double* z_mj_c_pt = z_m[j][1].values_pt();
3512 
3513  // Loop over the entries in x and update them
3514  for (unsigned i = 0; i < n_row; i++)
3515  {
3516  // Update the real part of the i-th entry in x
3517  block_update_r_pt[i] +=
3518  (z_mj_r_pt[i] * y[j].real()) - (z_mj_c_pt[i] * y[j].imag());
3519 
3520  // Update the imaginary part of the i-th entry in x
3521  block_update_c_pt[i] +=
3522  (z_mj_c_pt[i] * y[j].real()) + (z_mj_r_pt[i] * y[j].imag());
3523  }
3524  } // for (unsigned j=0;j<=k;j++)
3525 
3526  // Use the update: x_m=x_0+inv(M)Vy [see Saad Y,"Iterative methods for
3527  // sparse linear systems", p.284]
3528  for (unsigned dof_type = 0; dof_type < 2; dof_type++)
3529  {
3530  // Update the solution
3531  x[dof_type] += block_update[dof_type];
3532  }
3533  } // End of update
AnnoyingScalar imag(const AnnoyingScalar &)
Definition: AnnoyingScalar.h:132
Scalar * y
Definition: level1_cplx_impl.h:128
list x
Definition: plotDoE.py:28

References oomph::DistributableLinearAlgebraObject::distribution_pt(), hessenberg(), i, imag(), j, k, s, plotDoE::x, and y.

Referenced by smc.smc::recursiveBayesian().


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