oomph::ComplexDampedJacobi< MATRIX > Class Template Reference

#include <complex_smoother.h>

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

Public Member Functions

 ComplexDampedJacobi (const double &omega=0.5)
 Constructor (empty) More...
 
 ~ComplexDampedJacobi ()
 Empty destructor. More...
 
void clean_up_memory ()
 Cleanup data that's stored for resolve (if any has been stored) More...
 
 ComplexDampedJacobi (const ComplexDampedJacobi &)=delete
 Broken copy constructor. More...
 
void operator= (const ComplexDampedJacobi &)=delete
 Broken assignment operator. More...
 
void calculate_omega (const double &k, const double &h)
 
doubleomega ()
 Get access to the value of Omega (lvalue) More...
 
void complex_smoother_setup (Vector< CRDoubleMatrix * > helmholtz_matrix_pt)
 Setup: Pass pointer to the matrix and store in cast form. More...
 
void complex_smoother_solve (const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
 
void solve (Problem *const &problem_pt, DoubleVector &result)
 
unsigned iterations () const
 Number of iterations taken. More...
 
- Public Member Functions inherited from oomph::HelmholtzSmoother
 HelmholtzSmoother ()
 Empty constructor. More...
 
virtual ~HelmholtzSmoother ()
 Virtual empty destructor. More...
 
void complex_matrix_multiplication (Vector< CRDoubleMatrix * > matrices_pt, const Vector< DoubleVector > &x, Vector< DoubleVector > &soln)
 
template<typename MATRIX >
void check_validity_of_solve_helper_inputs (CRDoubleMatrix *const &real_matrix_pt, CRDoubleMatrix *const &imag_matrix_pt, const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution, const double &n_dof)
 
- 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 disable_resolve ()
 
virtual void solve (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &result)
 
virtual void solve (DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
 
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 (const DoubleVector &rhs, DoubleVector &result)
 
virtual void resolve_transpose (const DoubleVector &rhs, DoubleVector &result)
 
virtual void enable_computation_of_gradient ()
 
void disable_computation_of_gradient ()
 
void reset_gradient ()
 
void get_gradient (DoubleVector &gradient)
 function to access the gradient, provided it has been computed More...
 
- Public Member Functions inherited from oomph::DistributableLinearAlgebraObject
 DistributableLinearAlgebraObject ()
 Default constructor - create a distribution. More...
 
 DistributableLinearAlgebraObject (const DistributableLinearAlgebraObject &matrix)=delete
 Broken copy constructor. More...
 
void operator= (const DistributableLinearAlgebraObject &)=delete
 Broken assignment operator. More...
 
virtual ~DistributableLinearAlgebraObject ()
 Destructor. More...
 
LinearAlgebraDistributiondistribution_pt () const
 access to the LinearAlgebraDistribution More...
 
unsigned nrow () const
 access function to the number of global rows. More...
 
unsigned nrow_local () const
 access function for the num of local rows on this processor. More...
 
unsigned nrow_local (const unsigned &p) const
 access function for the num of local rows on this processor. More...
 
unsigned first_row () const
 access function for the first row on this processor More...
 
unsigned first_row (const unsigned &p) const
 access function for the first row on this processor More...
 
bool distributed () const
 distribution is serial or distributed More...
 
bool distribution_built () const
 
void build_distribution (const LinearAlgebraDistribution *const dist_pt)
 
void build_distribution (const LinearAlgebraDistribution &dist)
 

Private Member Functions

void complex_solve_helper (const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
 This is where the actual work is done. More...
 

Private Attributes

bool Matrix_can_be_deleted
 
CRDoubleMatrixMatrix_real_pt
 Pointer to the real part of the system matrix. More...
 
CRDoubleMatrixMatrix_imag_pt
 Pointer to the real part of the system matrix. More...
 
Vector< doubleMatrix_diagonal_real
 Vector containing the diagonal entries of A_r (real(A)) More...
 
Vector< doubleMatrix_diagonal_imag
 Vector containing the diagonal entries of A_c (imag(A)) More...
 
Vector< doubleMatrix_diagonal_inv_sq
 Vector whose j'th entry is given by 1/(A_r(j,j)^2 + A_c(j,j)^2) More...
 
unsigned Iterations
 Number of iterations taken. More...
 
double Omega
 Damping factor. More...
 

Additional Inherited Members

- Protected Member Functions inherited from oomph::DistributableLinearAlgebraObject
void clear_distribution ()
 
- Protected Attributes inherited from oomph::HelmholtzSmoother
bool Use_as_smoother
 
- 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::ComplexDampedJacobi< MATRIX >

//////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// Damped Jacobi "solver" templated by matrix type. The "solver" exists in many different incarnations: It's an IterativeLinearSolver, and a Smoother, all of which use the same basic iteration.

Constructor & Destructor Documentation

◆ ComplexDampedJacobi() [1/2]

template<typename MATRIX >
oomph::ComplexDampedJacobi< MATRIX >::ComplexDampedJacobi ( const double omega = 0.5)
inline

Constructor (empty)

286  : Matrix_can_be_deleted(true),
287  Matrix_real_pt(0),
288  Matrix_imag_pt(0),
289  Omega(omega){};
bool Matrix_can_be_deleted
Definition: complex_smoother.h:504
CRDoubleMatrix * Matrix_imag_pt
Pointer to the real part of the system matrix.
Definition: complex_smoother.h:510
double & omega()
Get access to the value of Omega (lvalue)
Definition: complex_smoother.h:391
double Omega
Damping factor.
Definition: complex_smoother.h:525
CRDoubleMatrix * Matrix_real_pt
Pointer to the real part of the system matrix.
Definition: complex_smoother.h:507

◆ ~ComplexDampedJacobi()

template<typename MATRIX >
oomph::ComplexDampedJacobi< MATRIX >::~ComplexDampedJacobi ( )
inline

Empty destructor.

293  {
294  // Run clean_up_memory
295  clean_up_memory();
296  } // End of ~ComplexDampedJacobi
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
Definition: complex_smoother.h:299

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

◆ ComplexDampedJacobi() [2/2]

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

Broken copy constructor.

Member Function Documentation

◆ calculate_omega()

template<typename MATRIX >
void oomph::ComplexDampedJacobi< MATRIX >::calculate_omega ( const double k,
const double h 
)
inline

Function to calculate the value of Omega by passing in the value of k and h [see Elman et al. "A multigrid method enhanced by Krylov subspace iteration for discrete Helmholtz equations", p.1303]

334  {
335  // Create storage for the parameter kh
336  double kh = k * h;
337 
338  // Store the value of pi
339  double pi = MathematicalConstants::Pi;
340 
341  // Calculate the value of Omega
342  double omega = (12.0 - 4.0 * pow(kh, 2.0)) / (18.0 - 3.0 * pow(kh, 2.0));
343 
344  // Set the tolerance for how close omega can be to 0
345  double tolerance = 1.0e-03;
346 
347  // Only store the value of omega if it lies in the range (0,1]. If it
348  // isn't it will produce a divergent scheme. Note, to avoid letting
349  // omega become too small we make sure it is greater than some tolerance
350  if ((omega > tolerance) && !(omega > 1))
351  {
352  // Since omega lies in the specified range, store it
353  Omega = omega;
354  }
355  // On the coarsest grids: if the wavenumber is greater than pi and
356  // kh>2cos(pi*h/2) then we can choose omega from the range (0,omega_2)
357  // where omega_2 is defined in [Elman et al."A multigrid method
358  // enhanced by Krylov subspace iteration for discrete Helmholtz
359  // equations", p.1295]
360  else if ((k > pi) && (kh > 2 * cos(pi * h / 2)))
361  {
362  // Calculate the numerator of omega_2
363  double omega_2 = (2.0 - pow(kh, 2.0));
364 
365  // Divide by the denominator of the fraction
366  omega_2 /= (2.0 * pow(sin(pi * h / 2), 2.0) - 0.5 * pow(kh, 2.0));
367 
368  // If 2/3 lies in the range (0,omega_2), use it
369  if (omega_2 > (2.0 / 3.0))
370  {
371  // Assign Omega the damping factor used for the Poisson equation
372  Omega = 2.0 / 3.0;
373  }
374  // If omega_2 is less than 2/3 use the midpoint of (tolerance,omega_2)
375  else
376  {
377  // Set the value of Omega
378  Omega = 0.5 * (tolerance + omega_2);
379  }
380  }
381  // Since the value of kh must be fairly large, make the value of
382  // omega small to compensate
383  else
384  {
385  // Since kh doesn't lie in the chosen range, set it to some small value
386  Omega = 0.2;
387  }
388  } // End of calculate_omega
AnnoyingScalar cos(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:136
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
double & tolerance()
Access to convergence tolerance.
Definition: iterative_linear_solver.h:107
char char char int int * k
Definition: level2_impl.h:374
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
const Mdouble pi
Definition: ExtendedMath.h:23
const double Pi
50 digits from maple
Definition: oomph_utilities.h:157

References cos(), k, oomph::ComplexDampedJacobi< MATRIX >::omega(), oomph::ComplexDampedJacobi< MATRIX >::Omega, constants::pi, oomph::MathematicalConstants::Pi, Eigen::bfloat16_impl::pow(), sin(), and oomph::IterativeLinearSolver::tolerance().

Referenced by oomph::HelmholtzMGPreconditioner< DIM >::setup_smoothers().

◆ clean_up_memory()

template<typename MATRIX >
void oomph::ComplexDampedJacobi< MATRIX >::clean_up_memory ( )
inlinevirtual

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

Reimplemented from oomph::LinearSolver.

300  {
301  // If the real matrix pointer isn't null AND we're allowed to delete
302  // the matrix which is only when we create the matrix ourselves
303  if ((Matrix_real_pt != 0) && (Matrix_can_be_deleted))
304  {
305  // Delete the matrix
306  delete Matrix_real_pt;
307 
308  // Assign the associated pointer the value NULL
309  Matrix_real_pt = 0;
310  }
311 
312  // If the real matrix pointer isn't null AND we're allowed to delete
313  // the matrix which is only when we create the matrix ourselves
314  if ((Matrix_imag_pt != 0) && (Matrix_can_be_deleted))
315  {
316  // Delete the matrix
317  delete Matrix_imag_pt;
318 
319  // Assign the associated pointer the value NULL
320  Matrix_imag_pt = 0;
321  }
322  } // End of clean_up_memory

References oomph::ComplexDampedJacobi< MATRIX >::Matrix_can_be_deleted, oomph::ComplexDampedJacobi< MATRIX >::Matrix_imag_pt, and oomph::ComplexDampedJacobi< MATRIX >::Matrix_real_pt.

Referenced by oomph::ComplexDampedJacobi< MATRIX >::~ComplexDampedJacobi().

◆ complex_smoother_setup()

template<typename MATRIX >
void oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_setup ( Vector< CRDoubleMatrix * >  helmholtz_matrix_pt)
inlinevirtual

Setup: Pass pointer to the matrix and store in cast form.

Implements oomph::HelmholtzSmoother.

399  {
400  // Assume the matrices have been passed in from the outside so we must
401  // not delete it. This is needed to avoid pre- and post-smoothers
402  // deleting the same matrix in the MG solver. If this was originally
403  // set to TRUE then this will be sorted out in the other functions
404  // from which this was called
405  Matrix_can_be_deleted = false;
406 
407  // Assign the real matrix pointers
408  Matrix_real_pt = helmholtz_matrix_pt[0];
409 
410  // Assign the imaginary matrix pointers
411  Matrix_imag_pt = helmholtz_matrix_pt[1];
412 
413 #ifdef PARANOID
414  // PARANOID check that if the matrix is distributable. If it is not then
415  // it should not be distributed
416  if (Matrix_real_pt->nrow() != Matrix_imag_pt->nrow())
417  {
418  std::ostringstream error_message_stream;
419  error_message_stream << "Incompatible real and complex matrix sizes.";
420  throw OomphLibError(error_message_stream.str(),
423  }
424 #endif
425 
426  //--------------------------------------------------------------------
427  // We need the matrix diagonals to calculate inv(D) (where D is the
428  // diagonal of A) as it remains the same for each use of the iterative
429  // scheme. To avoid unnecessary computations we store it now so it can
430  // simply be called in each iteration.
431  //--------------------------------------------------------------------
432 
433  // Grab the diagonal entries of the real part of the system matrix
435 
436  // Grab the diagonal entries of the imaginary part of the system matrix
438 
439  // Find the number of entries in the vectors containing the diagonal
440  // entries of both the real and the imaginary matrix
441  unsigned n_dof = Matrix_diagonal_real.size();
442 
443  // Make a dummy vector to store the entries of Matrix_diagonal_inv_sq
444  Matrix_diagonal_inv_sq.resize(n_dof, 0.0);
445 
446  // Create a helper variable to store A_r(j,j), for some j
447  double dummy_r;
448 
449  // Create a helper variable to store A_c(j,j), for some j
450  double dummy_c;
451 
452  // Loop over the entries of Matrix_diagonal_inv_sq and set the i-th
453  // entry to 1/(A_r(i,i)^2 + A_c(i,i)^2)
454  for (unsigned i = 0; i < n_dof; i++)
455  {
456  // Store the value of A_r(i,i)
457  dummy_r = Matrix_diagonal_real[i];
458 
459  // Store the value of A_c(i,i)
461 
462  // Store the value of 1/(A_r(i,i)^2 + A_c(i,i)^2)
464  1.0 / (dummy_r * dummy_r + dummy_c * dummy_c);
465  }
466  } // End of complex_smoother_setup
int i
Definition: BiCGSTAB_step_by_step.cpp:9
unsigned long nrow() const
Return the number of rows of the matrix.
Definition: matrices.h:1002
Vector< double > diagonal_entries() const
Definition: matrices.cc:3465
Vector< double > Matrix_diagonal_inv_sq
Vector whose j'th entry is given by 1/(A_r(j,j)^2 + A_c(j,j)^2)
Definition: complex_smoother.h:519
Vector< double > Matrix_diagonal_real
Vector containing the diagonal entries of A_r (real(A))
Definition: complex_smoother.h:513
Vector< double > Matrix_diagonal_imag
Vector containing the diagonal entries of A_c (imag(A))
Definition: complex_smoother.h:516
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
Definition: meta.cpp:172

References oomph::CRDoubleMatrix::diagonal_entries(), i, oomph::ComplexDampedJacobi< MATRIX >::Matrix_can_be_deleted, oomph::ComplexDampedJacobi< MATRIX >::Matrix_diagonal_imag, oomph::ComplexDampedJacobi< MATRIX >::Matrix_diagonal_inv_sq, oomph::ComplexDampedJacobi< MATRIX >::Matrix_diagonal_real, oomph::ComplexDampedJacobi< MATRIX >::Matrix_imag_pt, oomph::ComplexDampedJacobi< MATRIX >::Matrix_real_pt, oomph::CRDoubleMatrix::nrow(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ complex_smoother_solve()

template<typename MATRIX >
void oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_solve ( const Vector< DoubleVector > &  rhs,
Vector< DoubleVector > &  solution 
)
inlinevirtual

The smoother_solve function performs fixed number of iterations on the system A*result=rhs. The number of (smoothing) iterations is the same as the max. number of iterations in the underlying IterativeLinearSolver class.

Implements oomph::HelmholtzSmoother.

474  {
475  // If you use a smoother but you don't want to calculate the residual
476  Use_as_smoother = true;
477 
478  // Call the helper function
480  } // End of complex_smoother_solve
void complex_solve_helper(const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
This is where the actual work is done.
Definition: complex_smoother.h:532
bool Use_as_smoother
Definition: complex_smoother.h:176
void solution(const Vector< double > &x, Vector< double > &u)
Definition: two_d_biharmonic.cc:113

References oomph::ComplexDampedJacobi< MATRIX >::complex_solve_helper(), BiharmonicTestFunctions1::solution(), and oomph::HelmholtzSmoother::Use_as_smoother.

◆ complex_solve_helper()

template<typename MATRIX >
void oomph::ComplexDampedJacobi< MATRIX >::complex_solve_helper ( const Vector< DoubleVector > &  rhs,
Vector< DoubleVector > &  solution 
)
private

This is where the actual work is done.

\[ \|a\|_2^2=\sum_{i=0}^{i=n-1}\real(a[i])^2+\imag(a[i])^2. \]

\[ \|a\|_2^2=\|\real(a)\|_2^2+\|\imag(a)\|_2^2. \]

534  {
535  // Get number of dofs
536  unsigned n_dof = Matrix_real_pt->nrow();
537 
538 #ifdef PARANOID
539  // Upcast the matrix to the appropriate type
540  CRDoubleMatrix* tmp_rmatrix_pt =
541  dynamic_cast<CRDoubleMatrix*>(Matrix_real_pt);
542 
543  // Upcast the matrix to the appropriate type
544  CRDoubleMatrix* tmp_imatrix_pt =
545  dynamic_cast<CRDoubleMatrix*>(Matrix_imag_pt);
546 
547  // PARANOID Run the self-tests to check the inputs are correct
548  this->check_validity_of_solve_helper_inputs<MATRIX>(
549  tmp_rmatrix_pt, tmp_imatrix_pt, rhs, solution, n_dof);
550 
551  // We don't need the real matrix pointer any more
552  tmp_rmatrix_pt = 0;
553 
554  // We don't need the imaginary matrix pointer any more
555  tmp_imatrix_pt = 0;
556 #endif
557 
558  // Setup the solution if it is not
559  if ((!solution[0].distribution_pt()->built()) ||
560  (!solution[1].distribution_pt()->built()))
561  {
562  solution[0].build(rhs[0].distribution_pt(), 0.0);
563  solution[1].build(rhs[1].distribution_pt(), 0.0);
564  }
565 
566  // Initialise timer
567  double t_start = TimingHelpers::timer();
568 
569  // Copy the real and imaginary part of the solution vector
570  DoubleVector x_real(solution[0]);
571  DoubleVector x_imag(solution[1]);
572 
573  // Copy the real and imaginary part of the RHS vector
574  DoubleVector rhs_real(rhs[0]);
575  DoubleVector rhs_imag(rhs[1]);
576 
577  // Create storage for the real and imaginary part of the constant term
578  DoubleVector constant_term_real(this->distribution_pt(), 0.0);
579  DoubleVector constant_term_imag(this->distribution_pt(), 0.0);
580 
581  // Create storage for the real and imaginary part of the residual vector.
582  // These aren't used/built if we're inside the multigrid solver
583  DoubleVector residual_real;
584  DoubleVector residual_imag;
585 
586  // Create storage for the norm of the real and imaginary parts of the
587  // residual vector. These aren't used if we're inside the multigrid
588  // solver
589  double res_real_norm = 0.0;
590  double res_imag_norm = 0.0;
591 
592  // Variable to hold the current residual norm. This isn't used if
593  // we're inside the multigrid solver
594  double norm_res = 0.0;
595 
596  // Variables to hold the initial residual norm. This isn't used if
597  // we're inside the multigrid solver
598  double norm_f = 0.0;
599 
600  // Initialise the value of Iterations
601  Iterations = 0;
602 
603  //------------------------------------------------------------------------
604  // Initial guess isn't necessarily zero (restricted solution from finer
605  // grids) therefore both x and the residual need to be assigned values
606  // from inputs. The constant term at the end of the stationary iteration
607  // is also calculated here since it does not change at all throughout the
608  // iterative process:
609  //------------------------------------------------------------------------
610 
611  // Loop over all the entries of each vector
612  for (unsigned i = 0; i < n_dof; i++)
613  {
614  // Calculate the numerator of the i'th entry in the real component of
615  // the constant term
616  constant_term_real[i] = (Matrix_diagonal_real[i] * rhs_real[i] +
617  Matrix_diagonal_imag[i] * rhs_imag[i]);
618 
619  // Divide by the denominator
620  constant_term_real[i] *= Matrix_diagonal_inv_sq[i];
621 
622  // Scale by the damping factor
623  constant_term_real[i] *= Omega;
624 
625  // Calculate the numerator of the i'th entry in the imaginary component of
626  // the constant term
627  constant_term_imag[i] = (Matrix_diagonal_real[i] * rhs_imag[i] -
628  Matrix_diagonal_imag[i] * rhs_real[i]);
629 
630  // Divide by the denominator
631  constant_term_imag[i] *= Matrix_diagonal_inv_sq[i];
632 
633  // Scale by the damping factor
634  constant_term_imag[i] *= Omega;
635  }
636 
637  // Create 4 temporary vectors to store the various matrix-vector products
638  // required. The appropriate combination has been appended to the name. For
639  // instance, the product A_r*x_c corresponds to temp_vec_rc (real*imag)
640  DoubleVector temp_vec_rr(this->distribution_pt(), 0.0);
641  DoubleVector temp_vec_cc(this->distribution_pt(), 0.0);
642  DoubleVector temp_vec_rc(this->distribution_pt(), 0.0);
643  DoubleVector temp_vec_cr(this->distribution_pt(), 0.0);
644 
645  // Calculate the different combinations of A*x (or A*e depending on the
646  // level in the heirarchy) in the complex case (i.e. A_r*x_r, A_c*x_c,
647  // A_r*x_c and A_c*x_r)
648  Matrix_real_pt->multiply(x_real, temp_vec_rr);
649  Matrix_imag_pt->multiply(x_imag, temp_vec_cc);
650  Matrix_real_pt->multiply(x_imag, temp_vec_rc);
651  Matrix_imag_pt->multiply(x_real, temp_vec_cr);
652 
653  //---------------------------------------------------------------------------
654  // Calculating the residual r=b-Ax in the complex case requires more care
655  // than the real case. The correct calculation can be derived rather easily.
656  // Consider the splitting of A, x and b into their complex components:
657  // r = b - A*x
658  // = (b_r + i*b_c) - (A_r + i*A_c)*(x_r + i*x_c)
659  // = [b_r - A_r*x_r + A_c*x_c] + i*[b_c - A_r*x_c - A_c*x_r]
660  // ==> real(r) = b_r - A_r*x_r + A_c*x_c
661  // & imag(r) = b_c - A_r*x_c - A_c*x_r.
662  //---------------------------------------------------------------------------
663 
664  // Calculate the residual only if we're not inside the multigrid solver
665  if (!Use_as_smoother)
666  {
667  // Create storage for the real and imaginary part of the residual vector
668  residual_real.build(this->distribution_pt(), 0.0);
669  residual_imag.build(this->distribution_pt(), 0.0);
670 
671  // Real part of the residual:
672  residual_real = rhs_real;
673  residual_real -= temp_vec_rr;
674  residual_real += temp_vec_cc;
675 
676  // Imaginary part of the residual:
677  residual_imag = rhs_imag;
678  residual_imag -= temp_vec_rc;
679  residual_imag -= temp_vec_cr;
680 
681  // Calculate the 2-norm (noting that the 2-norm of a complex vector a of
682  // length n is simply the square root of the sum of the squares of each
683  // real and imaginary component). That is:
685  // can be written as:
687  double res_real_norm = residual_real.norm();
688  double res_imag_norm = residual_imag.norm();
689  double norm_res =
690  sqrt(res_real_norm * res_real_norm + res_imag_norm * res_imag_norm);
691 
692  // If required will document convergence history to screen
693  // or file (if stream is open)
695  {
696  if (!Output_file_stream.is_open())
697  {
698  oomph_info << Iterations << " " << norm_res << std::endl;
699  }
700  else
701  {
702  Output_file_stream << Iterations << " " << norm_res << std::endl;
703  }
704  } // if (Doc_convergence_history)
705  } // if (!Use_as_smoother)
706 
707  // Two temporary vectors to store the value of A_r*x_r - A_c*x_c and
708  // A_c*x_r + A_r*x_c in each iteration
709  DoubleVector temp_vec_real(this->distribution_pt(), 0.0);
710  DoubleVector temp_vec_imag(this->distribution_pt(), 0.0);
711 
712  // Calculate A_r*x_r - A_c*x_c
713  temp_vec_real = temp_vec_rr;
714  temp_vec_real -= temp_vec_cc;
715 
716  // Calculate A_c*x_r + A_r*x_c
717  temp_vec_imag = temp_vec_cr;
718  temp_vec_imag += temp_vec_rc;
719 
720  // Outermost loop: Run up to Max_iter times
721  for (unsigned iter_num = 0; iter_num < Max_iter; iter_num++)
722  {
723  // Loop over each degree of freedom and update
724  // the current approximation
725  for (unsigned i = 0; i < n_dof; i++)
726  {
727  // Make a couple of dummy variables to help with calculations
728  double dummy_r = 0.0;
729  double dummy_c = 0.0;
730 
731  // Calculate one part of the correction term (real)
732  dummy_r = (Matrix_diagonal_real[i] * temp_vec_real[i] +
733  Matrix_diagonal_imag[i] * temp_vec_imag[i]);
734 
735  // Calculate one part of the correction term (imaginary)
736  dummy_c = (Matrix_diagonal_real[i] * temp_vec_imag[i] -
737  Matrix_diagonal_imag[i] * temp_vec_real[i]);
738 
739  // Scale by Omega/([A(i,i)_r]^2+[A(i,i)_c]^2)
740  dummy_r *= Omega * Matrix_diagonal_inv_sq[i];
742 
743  // Update the value of x_real
744  x_real[i] -= dummy_r;
745  x_imag[i] -= dummy_c;
746  }
747 
748  // Update the value of x (or e depending on the level in the heirarchy)
749  x_real += constant_term_real;
750  x_imag += constant_term_imag;
751 
752  // Calculate the different combinations of A*x (or A*e depending on the
753  // level in the heirarchy) in the complex case (i.e. A_r*x_r, A_c*x_c,
754  // A_r*x_c and A_c*x_r)
755  Matrix_real_pt->multiply(x_real, temp_vec_rr);
756  Matrix_imag_pt->multiply(x_imag, temp_vec_cc);
757  Matrix_real_pt->multiply(x_imag, temp_vec_rc);
758  Matrix_imag_pt->multiply(x_real, temp_vec_cr);
759 
760  // Calculate A_r*x_r - A_c*x_c
761  temp_vec_real = temp_vec_rr;
762  temp_vec_real -= temp_vec_cc;
763 
764  // Calculate A_c*x_r + A_r*x_c
765  temp_vec_imag = temp_vec_cr;
766  temp_vec_imag += temp_vec_rc;
767 
768  // Calculate the residual only if we're not inside the multigrid solver
769  if (!Use_as_smoother)
770  {
771  // Calculate the residual
772  residual_real = rhs_real;
773  residual_real -= temp_vec_rr;
774  residual_real += temp_vec_cc;
775 
776  // Calculate the imaginary part of the residual vector
777  residual_imag = rhs_imag;
778  residual_imag -= temp_vec_rc;
779  residual_imag -= temp_vec_cr;
780 
781  // Calculate the 2-norm using the method mentioned previously
782  res_real_norm = residual_real.norm();
783  res_imag_norm = residual_imag.norm();
784  norm_res =
785  sqrt(res_real_norm * res_real_norm + res_imag_norm * res_imag_norm) /
786  norm_f;
787 
788  // If required, this will document convergence history to
789  // screen or file (if the stream is open)
791  {
792  if (!Output_file_stream.is_open())
793  {
794  oomph_info << Iterations << " " << norm_res << std::endl;
795  }
796  else
797  {
798  Output_file_stream << Iterations << " " << norm_res << std::endl;
799  }
800  } // if (Doc_convergence_history)
801 
802  // Check the tolerance only if the residual norm is being computed
803  if (norm_res < Tolerance)
804  {
805  // Break out of the for-loop
806  break;
807  }
808  } // if (!Use_as_smoother)
809  } // for (unsigned iter_num=0;iter_num<Max_iter;iter_num++)
810 
811  // Calculate the residual only if we're not inside the multigrid solver
812  if (!Use_as_smoother)
813  {
814  // If time documentation is enabled
815  if (Doc_time)
816  {
817  oomph_info << "\n(Complex) damped Jacobi converged. Residual norm: "
818  << norm_res
819  << "\nNumber of iterations to convergence: " << Iterations
820  << "\n"
821  << std::endl;
822  }
823  } // if (!Use_as_smoother)
824 
825  // Copy the solution into the solution vector
826  solution[0] = x_real;
827  solution[1] = x_imag;
828 
829  // Doc time for solver
830  double t_end = TimingHelpers::timer();
831  Solution_time = t_end - t_start;
832  if (Doc_time)
833  {
834  oomph_info << "Time for solve with (complex) damped Jacobi [sec]: "
835  << Solution_time << std::endl;
836  }
837 
838  // If the solver failed to converge and the user asked for an error if
839  // this happened
841  {
842  std::string error_message =
843  "Solver failed to converge and you requested ";
844  error_message += "an error on convergence failures.";
845  throw OomphLibError(
847  }
848  } // End of complex_solve_helper function
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
void multiply(const DoubleVector &x, DoubleVector &soln) const
Multiply the matrix by the vector x: soln=Ax.
Definition: matrices.cc:1782
unsigned Iterations
Number of iterations taken.
Definition: complex_smoother.h:522
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
Definition: linear_algebra_distribution.h:457
double Tolerance
Convergence tolerance.
Definition: iterative_linear_solver.h:239
bool Throw_error_after_max_iter
Definition: iterative_linear_solver.h:262
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 Doc_time
Boolean flag that indicates whether the time taken.
Definition: linear_solver.h:77
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
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(), i, Global_Variables::Iterations, oomph::BlackBoxFDNewtonSolver::Max_iter, oomph::DoubleVector::norm(), oomph::SarahBL::Omega, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, BiharmonicTestFunctions1::solution(), sqrt(), oomph::Global_string_for_annotation::string(), and oomph::TimingHelpers::timer().

Referenced by oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_solve().

◆ iterations()

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

Number of iterations taken.

Implements oomph::IterativeLinearSolver.

493  {
494  return Iterations;
495  }

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

◆ omega()

template<typename MATRIX >
double& oomph::ComplexDampedJacobi< MATRIX >::omega ( )
inline

Get access to the value of Omega (lvalue)

392  {
393  // Return the value of Omega
394  return Omega;
395  } // End of omega

References oomph::ComplexDampedJacobi< MATRIX >::Omega.

Referenced by oomph::ComplexDampedJacobi< MATRIX >::calculate_omega().

◆ operator=()

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

Broken assignment operator.

◆ solve()

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

Use damped Jacobi iteration as an IterativeLinearSolver: This obtains the Jacobian matrix J and the residual vector r (needed for the Newton method) from the problem's get_jacobian function and returns the result of Jx=r.

Implements oomph::LinearSolver.

487  {
488  BrokenCopy::broken_assign("ComplexDampedJacobi");
489  }
void broken_assign(const std::string &class_name)
Issue error message and terminate execution.
Definition: oomph_utilities.cc:195

References oomph::BrokenCopy::broken_assign().

Member Data Documentation

◆ Iterations

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

Number of iterations taken.

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

◆ Matrix_can_be_deleted

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

Boolean flag to indicate if the matrices pointed to by Matrix_real_pt and Matrix_imag_pt can be deleted.

Referenced by oomph::ComplexDampedJacobi< MATRIX >::clean_up_memory(), and oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_setup().

◆ Matrix_diagonal_imag

template<typename MATRIX >
Vector<double> oomph::ComplexDampedJacobi< MATRIX >::Matrix_diagonal_imag
private

Vector containing the diagonal entries of A_c (imag(A))

Referenced by oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_setup().

◆ Matrix_diagonal_inv_sq

template<typename MATRIX >
Vector<double> oomph::ComplexDampedJacobi< MATRIX >::Matrix_diagonal_inv_sq
private

Vector whose j'th entry is given by 1/(A_r(j,j)^2 + A_c(j,j)^2)

Referenced by oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_setup().

◆ Matrix_diagonal_real

template<typename MATRIX >
Vector<double> oomph::ComplexDampedJacobi< MATRIX >::Matrix_diagonal_real
private

Vector containing the diagonal entries of A_r (real(A))

Referenced by oomph::ComplexDampedJacobi< MATRIX >::complex_smoother_setup().

◆ Matrix_imag_pt

template<typename MATRIX >
CRDoubleMatrix* oomph::ComplexDampedJacobi< MATRIX >::Matrix_imag_pt
private

◆ Matrix_real_pt

template<typename MATRIX >
CRDoubleMatrix* oomph::ComplexDampedJacobi< MATRIX >::Matrix_real_pt
private

◆ Omega

template<typename MATRIX >
double oomph::ComplexDampedJacobi< MATRIX >::Omega
private

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