oomph::MGSolver< DIM > Class Template Reference

#include <geometric_multigrid.h>

+ Inheritance diagram for oomph::MGSolver< DIM >:

Public Types

typedef Smoother *(* PreSmootherFactoryFctPt) ()
 
typedef Smoother *(* PostSmootherFactoryFctPt) ()
 

Public Member Functions

void set_pre_smoother_factory_function (PreSmootherFactoryFctPt pre_smoother_fn)
 Access function to set the pre-smoother creation function. More...
 
void set_post_smoother_factory_function (PostSmootherFactoryFctPt post_smoother_fn)
 Access function to set the post-smoother creation function. More...
 
 MGSolver (MGProblem *mg_problem_pt)
 
 ~MGSolver ()
 Delete any dynamically allocated data. More...
 
void clean_up_memory ()
 Clean up anything that needs to be cleaned up. More...
 
void set_self_test_vector ()
 
void self_test ()
 
void restriction_self_test ()
 
void interpolation_self_test ()
 
void plot (const unsigned &hierarchy_level, const DoubleVector &input_vector, const std::string &filename)
 
void disable_v_cycle_output ()
 
void disable_output ()
 
void enable_v_cycle_output ()
 Enable the output of the V-cycle timings and other output. More...
 
void enable_doc_everything ()
 Enable the output from anything that could have been suppressed. More...
 
void enable_output ()
 Enable the output from anything that could have been suppressed. More...
 
void disable_smoother_and_superlu_doc_time ()
 Suppress the output of both smoothers and SuperLU. More...
 
unsignednpost_smooth ()
 Return the number of post-smoothing iterations (lvalue) More...
 
unsignednpre_smooth ()
 Return the number of pre-smoothing iterations (lvalue) More...
 
void pre_smooth (const unsigned &level)
 
void post_smooth (const unsigned &level)
 
double residual_norm (const unsigned &level)
 
void direct_solve ()
 Call the direct solver (SuperLU) to solve the problem exactly. More...
 
void interpolation_matrix_set (const unsigned &level, double *value, int *col_index, int *row_st, unsigned &ncol, unsigned &nnz)
 
void interpolation_matrix_set (const unsigned &level, Vector< double > &value, Vector< int > &col_index, Vector< int > &row_st, unsigned &ncol, unsigned &nrow)
 
void set_restriction_matrices_as_interpolation_transposes ()
 
void restrict_residual (const unsigned &level)
 
void interpolate_and_correct (const unsigned &level)
 
void level_up_local_coord_of_node (const int &son_type, Vector< double > &s)
 
void setup_interpolation_matrices ()
 Setup the interpolation matrix on each level. More...
 
void setup_interpolation_matrices_unstructured ()
 Setup the interpolation matrices. More...
 
void setup_transfer_matrices ()
 Setup the transfer matrices on each level. More...
 
void full_setup ()
 Runs a full setup of the MG solver. More...
 
void solve (Problem *const &problem_pt, DoubleVector &result)
 
unsigned iterations () const
 Number of iterations. More...
 
unsignedmax_iter ()
 Number of iterations. More...
 
void level_up_local_coord_of_node (const int &son_type, Vector< double > &s)
 
void level_up_local_coord_of_node (const int &son_type, Vector< double > &s)
 
- 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)
 

Protected Member Functions

void mg_solve (DoubleVector &result)
 Linear solver. More...
 
void modify_restriction_matrices ()
 Modify the restriction matrices. More...
 
- Protected Member Functions inherited from oomph::DistributableLinearAlgebraObject
void clear_distribution ()
 

Protected Attributes

unsigned Nvcycle
 
MGProblemMg_problem_pt
 
Vector< DoubleVectorRhs_mg_vectors_storage
 
bool Suppress_v_cycle_output
 
bool Suppress_all_output
 
std::ostream * Stream_pt
 
- 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
 

Private Member Functions

void setup_mg_hierarchy ()
 Set up the MG hierarchy. More...
 
void setup_mg_structures ()
 Set up the MG hierarchy structures. More...
 
void setup_smoothers ()
 Set up the smoothers on all levels. More...
 

Private Attributes

PreSmootherFactoryFctPt Pre_smoother_factory_function_pt
 Function to create pre-smoothers. More...
 
PostSmootherFactoryFctPt Post_smoother_factory_function_pt
 Function to create post-smoothers. More...
 
unsigned Nlevel
 The number of levels in the multigrid heirachy. More...
 
Vector< MGProblem * > Mg_hierarchy
 Vector containing pointers to problems in hierarchy. More...
 
Vector< CRDoubleMatrix * > Mg_matrices_storage_pt
 Vector to store the system matrices. More...
 
Vector< CRDoubleMatrix * > Interpolation_matrices_storage_pt
 Vector to store the interpolation matrices. More...
 
Vector< CRDoubleMatrix * > Restriction_matrices_storage_pt
 Vector to store the restriction matrices. More...
 
Vector< DoubleVectorX_mg_vectors_storage
 Vector to store the solution vectors (X_mg) More...
 
Vector< DoubleVectorResidual_mg_vectors_storage
 Vector to store the residual vectors. More...
 
Vector< DoubleVectorInterpolation_self_test_vectors_storage
 
Vector< DoubleVectorRestriction_self_test_vectors_storage
 
Vector< Smoother * > Pre_smoothers_storage_pt
 Vector to store the pre-smoothers. More...
 
Vector< Smoother * > Post_smoothers_storage_pt
 Vector to store the post-smoothers. More...
 
unsigned Npre_smooth
 Number of pre-smoothing steps. More...
 
unsigned Npost_smooth
 Number of post-smoothing steps. More...
 
bool Doc_everything
 
bool Has_been_setup
 Boolean variable to indicate whether or not the solver has been setup. More...
 
bool Has_been_solved
 
unsigned V_cycle_counter
 Pointer to counter for V-cycles. More...
 

Additional Inherited Members

- Static Protected Attributes inherited from oomph::IterativeLinearSolver
static IdentityPreconditioner Default_preconditioner
 

Detailed Description

template<unsigned DIM>
class oomph::MGSolver< DIM >

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

Member Typedef Documentation

◆ PostSmootherFactoryFctPt

template<unsigned DIM>
typedef Smoother*(* oomph::MGSolver< DIM >::PostSmootherFactoryFctPt) ()

typedef for a function that returns a pointer to an object of the class Smoother to be used as the post-smoother

◆ PreSmootherFactoryFctPt

template<unsigned DIM>
typedef Smoother*(* oomph::MGSolver< DIM >::PreSmootherFactoryFctPt) ()

typedef for a function that returns a pointer to an object of the class Smoother to be used as the pre-smoother

Constructor & Destructor Documentation

◆ MGSolver()

template<unsigned DIM>
oomph::MGSolver< DIM >::MGSolver ( MGProblem mg_problem_pt)
inline

Constructor: Set up default values for number of V-cycles and pre- and post-smoothing steps.

119  : Nvcycle(200),
120  Mg_problem_pt(mg_problem_pt),
122  Suppress_all_output(false),
123  Stream_pt(0),
126  Npre_smooth(2),
127  Npost_smooth(2),
128  Doc_everything(false),
129  Has_been_setup(false),
130  Has_been_solved(false)
131  {
132  // Set the tolerance in the base class
133  this->Tolerance = 1.0e-09;
134 
135  // Set the pointer to the finest level as the first
136  // entry in Mg_hierarchy
137  Mg_hierarchy.push_back(Mg_problem_pt);
138  } // End of MGSolver
double Tolerance
Convergence tolerance.
Definition: iterative_linear_solver.h:239
bool Suppress_all_output
Definition: geometric_multigrid.h:642
PostSmootherFactoryFctPt Post_smoother_factory_function_pt
Function to create post-smoothers.
Definition: geometric_multigrid.h:655
bool Doc_everything
Definition: geometric_multigrid.h:717
std::ostream * Stream_pt
Definition: geometric_multigrid.h:648
unsigned Npost_smooth
Number of post-smoothing steps.
Definition: geometric_multigrid.h:710
unsigned Nvcycle
Definition: geometric_multigrid.h:622
Vector< MGProblem * > Mg_hierarchy
Vector containing pointers to problems in hierarchy.
Definition: geometric_multigrid.h:673
bool Suppress_v_cycle_output
Definition: geometric_multigrid.h:637
unsigned Npre_smooth
Number of pre-smoothing steps.
Definition: geometric_multigrid.h:707
bool Has_been_setup
Boolean variable to indicate whether or not the solver has been setup.
Definition: geometric_multigrid.h:720
MGProblem * Mg_problem_pt
Definition: geometric_multigrid.h:626
bool Has_been_solved
Definition: geometric_multigrid.h:724
PreSmootherFactoryFctPt Pre_smoother_factory_function_pt
Function to create pre-smoothers.
Definition: geometric_multigrid.h:652

References oomph::MGSolver< DIM >::Mg_hierarchy, oomph::MGSolver< DIM >::Mg_problem_pt, and oomph::IterativeLinearSolver::Tolerance.

◆ ~MGSolver()

template<unsigned DIM>
oomph::MGSolver< DIM >::~MGSolver ( )
inline

Delete any dynamically allocated data.

142  {
143  // Run the function written to clean up the memory
144  clean_up_memory();
145  } // End of ~MGSolver
void clean_up_memory()
Clean up anything that needs to be cleaned up.
Definition: geometric_multigrid.h:148

References oomph::MGSolver< DIM >::clean_up_memory().

Member Function Documentation

◆ clean_up_memory()

template<unsigned DIM>
void oomph::MGSolver< DIM >::clean_up_memory ( )
inlinevirtual

Clean up anything that needs to be cleaned up.

Reimplemented from oomph::LinearSolver.

Reimplemented in oomph::MGPreconditioner< DIM >.

149  {
150  // We only need to destroy data if the solver has been set up and
151  // the data hasn't already been cleared
152  if (Has_been_setup)
153  {
154  // Loop over all of the levels in the hierarchy
155  for (unsigned i = 0; i < Nlevel - 1; i++)
156  {
157  // Delete the pre-smoother associated with this level
158  delete Pre_smoothers_storage_pt[i];
159 
160  // Make it a null pointer
162 
163  // Delete the post-smoother associated with this level
165 
166  // Make it a null pointer
168 
169  // Delete the system matrix associated with the i-th level
170  delete Mg_matrices_storage_pt[i];
171 
172  // Make it a null pointer
174  }
175 
176  // Loop over all but the coarsest of the levels in the hierarchy
177  for (unsigned i = 0; i < Nlevel - 1; i++)
178  {
179  // Delete the interpolation matrix associated with the i-th level
181 
182  // Make it a null pointer
184 
185  // Delete the restriction matrix associated with the i-th level
187 
188  // Make it a null pointer
190  }
191 
192  // If this solver has been set up then a hierarchy of problems
193  // will have been set up. If the user chose to document everything
194  // then the coarse-grid multigrid problems will have been kept alive
195  // which means we now have to loop over the coarse-grid levels and
196  // destroy them
197  if (Doc_everything)
198  {
199  // Loop over the levels
200  for (unsigned i = 1; i < Nlevel; i++)
201  {
202  // Delete the i-th level problem
203  delete Mg_hierarchy[i];
204 
205  // Make the associated pointer a null pointer
206  Mg_hierarchy[i] = 0;
207  }
208  } // if (Doc_everything)
209 
210  // Everything has been deleted now so we need to indicate that the
211  // solver is not set up
212  Has_been_setup = false;
213  } // if (Has_been_setup)
214  } // End of clean_up_memory
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Vector< Smoother * > Post_smoothers_storage_pt
Vector to store the post-smoothers.
Definition: geometric_multigrid.h:704
unsigned Nlevel
The number of levels in the multigrid heirachy.
Definition: geometric_multigrid.h:670
Vector< Smoother * > Pre_smoothers_storage_pt
Vector to store the pre-smoothers.
Definition: geometric_multigrid.h:701
Vector< CRDoubleMatrix * > Restriction_matrices_storage_pt
Vector to store the restriction matrices.
Definition: geometric_multigrid.h:682
Vector< CRDoubleMatrix * > Mg_matrices_storage_pt
Vector to store the system matrices.
Definition: geometric_multigrid.h:676
Vector< CRDoubleMatrix * > Interpolation_matrices_storage_pt
Vector to store the interpolation matrices.
Definition: geometric_multigrid.h:679

References oomph::MGSolver< DIM >::Doc_everything, oomph::MGSolver< DIM >::Has_been_setup, i, oomph::MGSolver< DIM >::Interpolation_matrices_storage_pt, oomph::MGSolver< DIM >::Mg_hierarchy, oomph::MGSolver< DIM >::Mg_matrices_storage_pt, oomph::MGSolver< DIM >::Nlevel, oomph::MGSolver< DIM >::Post_smoothers_storage_pt, oomph::MGSolver< DIM >::Pre_smoothers_storage_pt, and oomph::MGSolver< DIM >::Restriction_matrices_storage_pt.

Referenced by oomph::MGSolver< DIM >::~MGSolver().

◆ direct_solve()

template<unsigned DIM>
void oomph::MGSolver< DIM >::direct_solve ( )
inline

Call the direct solver (SuperLU) to solve the problem exactly.

393  {
394  // Get solution by direct solve:
395  Mg_matrices_storage_pt[Nlevel - 1]->solve(
397  } // End of direct_solve
Vector< DoubleVector > Rhs_mg_vectors_storage
Definition: geometric_multigrid.h:631
Vector< DoubleVector > X_mg_vectors_storage
Vector to store the solution vectors (X_mg)
Definition: geometric_multigrid.h:685

References oomph::MGSolver< DIM >::Mg_matrices_storage_pt, oomph::MGSolver< DIM >::Nlevel, oomph::MGSolver< DIM >::Rhs_mg_vectors_storage, and oomph::MGSolver< DIM >::X_mg_vectors_storage.

◆ disable_output()

template<unsigned DIM>
void oomph::MGSolver< DIM >::disable_output ( )
inline

Suppress anything that can be suppressed, i.e. any timings. Things like mesh adaptation can not however be silenced using this

257  {
258  // Set the value of Doc_time (inherited from LinearSolver) to false
259  Doc_time = false;
260 
261  // Enable the suppression of output from the V-cycle
263 
264  // Enable the suppression of everything
265  Suppress_all_output = true;
266 
267  // Store the output stream pointer
269 
270  // Now set the oomph_info stream pointer to the null stream to
271  // disable all possible output
273  } // End of disable_output
bool Doc_time
Boolean flag that indicates whether the time taken.
Definition: linear_solver.h:77
std::ostream *& stream_pt()
Access function for the stream pointer.
Definition: oomph_definitions.h:464
Nullstream oomph_nullstream
Single (global) instantiation of the Nullstream.
Definition: oomph_definitions.cc:313
OomphInfo oomph_info
Definition: oomph_definitions.cc:319

References oomph::LinearSolver::Doc_time, oomph::oomph_info, oomph::oomph_nullstream, oomph::MGSolver< DIM >::Stream_pt, oomph::OomphInfo::stream_pt(), oomph::MGSolver< DIM >::Suppress_all_output, and oomph::MGSolver< DIM >::Suppress_v_cycle_output.

◆ disable_smoother_and_superlu_doc_time()

template<unsigned DIM>
void oomph::MGSolver< DIM >::disable_smoother_and_superlu_doc_time ( )
inline

Suppress the output of both smoothers and SuperLU.

309  {
310  // Loop over all levels of the hierarchy
311  for (unsigned i = 0; i < Nlevel - 1; i++)
312  {
313  // Disable time documentation on each level (for each pre-smoother)
314  Pre_smoothers_storage_pt[i]->disable_doc_time();
315 
316  // Disable time documentation on each level (for each post-smoother)
317  Post_smoothers_storage_pt[i]->disable_doc_time();
318  }
319 
320  // We only do a direct solve on the coarsest level so this is the only
321  // place we need to silence SuperLU
323  ->linear_solver_pt()
324  ->disable_doc_time();
325  } // End of disable_smoother_and_superlu_doc_time

References i, oomph::MGSolver< DIM >::Mg_matrices_storage_pt, oomph::MGSolver< DIM >::Nlevel, oomph::MGSolver< DIM >::Post_smoothers_storage_pt, and oomph::MGSolver< DIM >::Pre_smoothers_storage_pt.

◆ disable_v_cycle_output()

template<unsigned DIM>
void oomph::MGSolver< DIM >::disable_v_cycle_output ( )
inline

Disable all output from mg_solve apart from the number of V-cycles used to solve the problem

246  {
247  // Set the value of Doc_time (inherited from LinearSolver) to false
248  Doc_time = false;
249 
250  // Enable the suppression of output from the V-cycle
252  } // End of disable_v_cycle_output

References oomph::LinearSolver::Doc_time, and oomph::MGSolver< DIM >::Suppress_v_cycle_output.

◆ enable_doc_everything()

template<unsigned DIM>
void oomph::MGSolver< DIM >::enable_doc_everything ( )
inline

Enable the output from anything that could have been suppressed.

287  {
288  // Enable the documentation of everything (if this is set to TRUE then
289  // the function self_test() will be run which outputs a solution
290  // represented on each level of the hierarchy
291  Doc_everything = true;
292  } // End of enable_doc_everything

References oomph::MGSolver< DIM >::Doc_everything.

◆ enable_output()

template<unsigned DIM>
void oomph::MGSolver< DIM >::enable_output ( )
inline

Enable the output from anything that could have been suppressed.

296  {
297  // Enable time documentation
298  Doc_time = true;
299 
300  // Enable output from everything during the full setup of the solver
301  Suppress_all_output = false;
302 
303  // Enable output from the MG solver
304  Suppress_v_cycle_output = false;
305  } // End of enable_output

References oomph::LinearSolver::Doc_time, oomph::MGSolver< DIM >::Suppress_all_output, and oomph::MGSolver< DIM >::Suppress_v_cycle_output.

◆ enable_v_cycle_output()

template<unsigned DIM>
void oomph::MGSolver< DIM >::enable_v_cycle_output ( )
inline

Enable the output of the V-cycle timings and other output.

277  {
278  // Enable time documentation
279  Doc_time = true;
280 
281  // Enable output from the MG solver
282  Suppress_v_cycle_output = false;
283  } // End of enable_v_cycle_output

References oomph::LinearSolver::Doc_time, and oomph::MGSolver< DIM >::Suppress_v_cycle_output.

◆ full_setup()

template<unsigned DIM>
void oomph::MGSolver< DIM >::full_setup

Runs a full setup of the MG solver.

Do a full setup (assumes everything will be setup around the MGProblem pointer given in the constructor)

827  {
828  // Initialise the timer start variable
829  double t_fs_start = 0.0;
830 
831  // If we're allowed to output
832  if (!Suppress_all_output)
833  {
834  // Start the timer
835  t_fs_start = TimingHelpers::timer();
836 
837  // Notify user that the hierarchy of levels is complete
838  oomph_info
839  << "\n===============Starting Multigrid Full Setup=============="
840  << std::endl;
841 
842  // Notify user that the hierarchy of levels is complete
843  oomph_info << "\nStarting the full setup of the multigrid solver."
844  << std::endl;
845  }
846 
847 #ifdef PARANOID
848  // PARANOID check - Make sure the dimension of the solver matches the
849  // dimension of the elements used in the problems mesh
850  if (dynamic_cast<FiniteElement*>(Mg_problem_pt->mesh_pt()->element_pt(0))
851  ->dim() != DIM)
852  {
853  std::string err_strng = "The dimension of the elements used in the mesh ";
854  err_strng += "does not match the dimension of the solver.";
855  throw OomphLibError(
857  }
858 
859  // PARANOID check - The elements of the bulk mesh must all be refineable
860  // elements otherwise we cannot deal with this
861  if (Mg_problem_pt->mg_bulk_mesh_pt() != 0)
862  {
863  // Find the number of elements in the bulk mesh
864  unsigned n_elements = Mg_problem_pt->mg_bulk_mesh_pt()->nelement();
865 
866  // Loop over the elements in the mesh and ensure that they are
867  // all refineable elements
868  for (unsigned el_counter = 0; el_counter < n_elements; el_counter++)
869  {
870  // Upcast global mesh element to a refineable element
871  RefineableElement* el_pt = dynamic_cast<RefineableElement*>(
872  Mg_problem_pt->mg_bulk_mesh_pt()->element_pt(el_counter));
873 
874  // Check if the upcast worked or not; if el_pt is a null pointer the
875  // element is not refineable
876  if (el_pt == 0)
877  {
878  throw OomphLibError(
879  "Element in global mesh could not be upcast to a refineable "
880  "element. We cannot deal with elements that are not refineable.",
883  }
884  }
885  }
886  else
887  {
888  throw OomphLibError(
889  "The provided bulk mesh pointer is set to be a null pointer. "
890  "The multigrid solver operates on the bulk mesh thus a pointer "
891  "to the correct mesh must be given.",
894  }
895 #endif
896 
897  // If this is not the first Newton step then we will already have things
898  // in storage. If this is the case, delete them
899  clean_up_memory();
900 
901  // Resize the Mg_hierarchy vector
902  Mg_hierarchy.resize(1, 0);
903 
904  // Set the pointer to the finest level as the first entry in Mg_hierarchy
906 
907  // Create the hierarchy of levels
909 
910  // Set up the interpolation and restriction matrices
912 
913  // Set up the data structures on each level, i.e. the system matrix,
914  // LHS and RHS vectors
916 
917  // Set up the smoothers on all of the levels
918  setup_smoothers();
919 
920  // If we do not want to document everything we want to delete all the
921  // coarse-grid problems
922  if (!Doc_everything)
923  {
924  // Loop over all of the coarser levels
925  for (unsigned i = 1; i < Nlevel; i++)
926  {
927  // Delete the i-th coarse-grid MGProblem
928  delete Mg_hierarchy[i];
929 
930  // Set it to be a null pointer
931  Mg_hierarchy[i] = 0;
932  }
933  }
934  // Otherwise, document everything!
935  else
936  {
937  // If the user wishes to document everything we run the self-test
938  self_test();
939  } // if (!Doc_everything)
940 
941  // Indicate that the full setup has been completed
942  Has_been_setup = true;
943 
944  // If we're allowed to output to the screen
945  if (!Suppress_all_output)
946  {
947  // Output the time taken to complete the full setup
948  double t_fs_end = TimingHelpers::timer();
949  double full_setup_time = t_fs_end - t_fs_start;
950 
951  // Output the CPU time
952  oomph_info << "\nCPU time for full setup [sec]: " << full_setup_time
953  << std::endl;
954 
955  // Notify user that the hierarchy of levels is complete
956  oomph_info
957  << "\n===============Multigrid Full Setup Complete=============="
958  << std::endl;
959  } // if (!Suppress_all_output)
960  } // End of full_setup
virtual TreeBasedRefineableMeshBase * mg_bulk_mesh_pt()=0
void setup_mg_structures()
Set up the MG hierarchy structures.
Definition: geometric_multigrid.h:1180
void setup_transfer_matrices()
Setup the transfer matrices on each level.
Definition: geometric_multigrid.h:1117
void self_test()
Definition: geometric_multigrid.h:2135
void setup_mg_hierarchy()
Set up the MG hierarchy.
Definition: geometric_multigrid.h:968
void setup_smoothers()
Set up the smoothers on all levels.
Definition: geometric_multigrid.h:1360
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:448
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1280
#define DIM
Definition: linearised_navier_stokes_elements.h:44
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
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References oomph::TerminateHelper::clean_up_memory(), oomph::FiniteElement::dim(), DIM, i, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::self_test(), oomph::Global_string_for_annotation::string(), and oomph::TimingHelpers::timer().

Referenced by oomph::MGPreconditioner< DIM >::setup(), and oomph::MGSolver< DIM >::solve().

◆ interpolate_and_correct()

template<unsigned DIM>
void oomph::MGSolver< DIM >::interpolate_and_correct ( const unsigned level)

Interpolate solution at current level onto next finer mesh and correct the solution x at that level

2044  {
2045 #ifdef PARANOID
2046  // Check to make sure we can actually restrict the vector
2047  if (!(level > 0))
2048  {
2049  throw OomphLibError("Input level exceeds the possible parameter choice.",
2052  }
2053 #endif
2054 
2055  // Build distribution of a temporary vector
2056  DoubleVector temp_soln(X_mg_vectors_storage[level - 1].distribution_pt());
2057 
2058  // Interpolate the solution vector
2059  Interpolation_matrices_storage_pt[level - 1]->multiply(
2060  X_mg_vectors_storage[level], temp_soln);
2061 
2062  // Update
2063  X_mg_vectors_storage[level - 1] += temp_soln;
2064  } // End of interpolate_and_correct
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
Definition: linear_algebra_distribution.h:457

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ interpolation_matrix_set() [1/2]

template<unsigned DIM>
void oomph::MGSolver< DIM >::interpolation_matrix_set ( const unsigned level,
double value,
int col_index,
int row_st,
unsigned ncol,
unsigned nnz 
)
inline

Builds a CRDoubleMatrix that is used to interpolate the residual between levels. The transpose can be used as the full weighting restriction.

408  {
409  // Dynamically allocate the interpolation matrix
410  Interpolation_matrices_storage_pt[level] = new CRDoubleMatrix;
411 
412  // Build the matrix
413  Interpolation_matrices_storage_pt[level]->build_without_copy(
414  ncol, nnz, value, col_index, row_st);
415  } // End of interpolation_matrix_set
squared absolute value
Definition: GlobalFunctions.h:87

References oomph::MGSolver< DIM >::Interpolation_matrices_storage_pt, and Eigen::value.

◆ interpolation_matrix_set() [2/2]

template<unsigned DIM>
void oomph::MGSolver< DIM >::interpolation_matrix_set ( const unsigned level,
Vector< double > &  value,
Vector< int > &  col_index,
Vector< int > &  row_st,
unsigned ncol,
unsigned nrow 
)
inline

Builds a CRDoubleMatrix that is used to interpolate the residual between levels. The transpose can be used as the full weighting restriction.

426  {
427  // Dynamically allocate the interpolation matrix
428  Interpolation_matrices_storage_pt[level] = new CRDoubleMatrix;
429 
430  // Make the distribution pointer
431  LinearAlgebraDistribution* dist_pt = new LinearAlgebraDistribution(
432  Mg_hierarchy[level]->communicator_pt(), nrow, false);
433 
434 #ifdef PARANOID
435 #ifdef OOMPH_HAS_MPI
436  // Set up the warning messages
437  std::string warning_message =
438  "Setup of interpolation matrix distribution ";
439  warning_message += "has not been tested with MPI.";
440 
441  // If we're not running the code in serial
442  if (dist_pt->communicator_pt()->nproc() > 1)
443  {
444  // Throw a warning
445  OomphLibWarning(
447  }
448 #endif
449 #endif
450 
451  // Build the matrix itself
452  Interpolation_matrices_storage_pt[level]->build(
453  dist_pt, ncol, value, col_index, row_st);
454 
455  // Delete the newly created distribution pointer
456  delete dist_pt;
457 
458  // Make it a null pointer
459  dist_pt = 0;
460  } // End of interpolation_matrix_set
unsigned nrow() const
access function to the number of global rows.
Definition: linear_algebra_distribution.h:463

References oomph::LinearAlgebraDistribution::communicator_pt(), oomph::MGSolver< DIM >::Interpolation_matrices_storage_pt, oomph::MGSolver< DIM >::Mg_hierarchy, oomph::OomphCommunicator::nproc(), oomph::DistributableLinearAlgebraObject::nrow(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::Global_string_for_annotation::string(), and Eigen::value.

◆ interpolation_self_test()

template<unsigned DIM>
void oomph::MGSolver< DIM >::interpolation_self_test

Make a self-test to make sure that the interpolation matrices are doing the same thing to interpolate the vectors up.

Function which implements a self-test to interpolate a vector up all of levels of the MG hierarchy and outputs the restricted vectors to file

2345  {
2346  // Set the start of the output file name. The full names will
2347  // set after we calculate the interpolated vectors
2348  std::string outputfile = "RESLT/interpolation_self_test";
2349 
2350  // Loop over the levels of the hierarchy in reverse order
2351  for (unsigned level = Nlevel - 1; level > 0; level--)
2352  {
2353  // Interpolate the vector up a level
2354  Interpolation_matrices_storage_pt[level - 1]->multiply(
2357  } // End of the for loop over the hierarchy levels
2358 
2359  for (unsigned level = 0; level < Nlevel; level++)
2360  {
2361  // Set output file name
2362  std::string filename = outputfile;
2363  std::stringstream string;
2364  string << level;
2365  filename += string.str();
2366  filename += ".dat";
2367 
2368  // Plot the RHS vector on the current level
2370 
2371  } // End of for-loop to output the RHS vector on each level
2372  } // End of interpolation_self_test
void plot(const unsigned &hierarchy_level, const DoubleVector &input_vector, const std::string &filename)
Definition: geometric_multigrid.h:2379
Vector< DoubleVector > Interpolation_self_test_vectors_storage
Definition: geometric_multigrid.h:693
string filename
Definition: MergeRestartFiles.py:39

References MergeRestartFiles::filename, PlanarWave::plot(), and oomph::Global_string_for_annotation::string().

◆ iterations()

template<unsigned DIM>
unsigned oomph::MGSolver< DIM >::iterations ( ) const
inlinevirtual

Number of iterations.

Implements oomph::IterativeLinearSolver.

596  {
597  // Return the number of V-cycles which have been done
598  return V_cycle_counter;
599  } // End of iterations
unsigned V_cycle_counter
Pointer to counter for V-cycles.
Definition: geometric_multigrid.h:727

References oomph::MGSolver< DIM >::V_cycle_counter.

◆ level_up_local_coord_of_node() [1/3]

void oomph::MGSolver< 2 >::level_up_local_coord_of_node ( const int son_type,
Vector< double > &  s 
)

Given the son type of the element and the local coordinate s of a given node in the son element, return the local coordinate s in its father element. 2D case.

39  {
40  // If the element is unrefined between the levels the local coordinate
41  // of the node in one element is the same as that in the other element
42  // therefore we only need to perform calculations if the levels are
43  // different (i.e. son_type is not OMEGA)
44  if (son_type != Tree::OMEGA)
45  {
46  // Scale the local coordinate from the range [-1,1]x[-1,1] to the range
47  // [0,1]x[0,1] to match the width of the local coordinate range of the
48  // fine element from the perspective of the father element. This
49  // then simply requires a shift of the coordinates to match which type
50  // of son element we're dealing with
51  s[0] = (s[0] + 1.0) / 2.0;
52  s[1] = (s[1] + 1.0) / 2.0;
53 
54  // Cases: The son_type determines how the local coordinates should be
55  // shifted to give the local coordinates in the coarse mesh element
56  switch (son_type)
57  {
58  // If we're dealing with the bottom-left element we need to shift
59  // the range [0,1]x[0,1] to [-1,0]x[-1,0]
60  case QuadTreeNames::SW:
61  s[0] -= 1;
62  s[1] -= 1;
63  break;
64 
65  // If we're dealing with the bottom-right element we need to shift
66  // the range [0,1]x[0,1] to [0,1]x[-1,0]
67  case QuadTreeNames::SE:
68  s[1] -= 1;
69  break;
70 
71  // If we're dealing with the top-right element we need to shift the
72  // range [0,1]x[0,1] to [0,1]x[0,1], i.e. nothing needs to be done
73  case QuadTreeNames::NE:
74  break;
75 
76  // If we're dealing with the top-left element we need to shift
77  // the range [0,1]x[0,1] to [-1,0]x[0,1]
78  case QuadTreeNames::NW:
79  s[0] -= 1;
80  break;
81  }
82  } // if son_type!=Tree::OMEGA
83  } // End of level_up_local_coord_of_node
static const int OMEGA
Default value for an unassigned neighbour.
Definition: tree.h:262
RealScalar s
Definition: level1_cplx_impl.h:130
@ SE
Definition: quadtree.h:57
@ NW
Definition: quadtree.h:58
@ NE
Definition: quadtree.h:59
@ SW
Definition: quadtree.h:56

References oomph::QuadTreeNames::NE, oomph::QuadTreeNames::NW, oomph::Tree::OMEGA, s, oomph::QuadTreeNames::SE, and oomph::QuadTreeNames::SW.

◆ level_up_local_coord_of_node() [2/3]

void oomph::MGSolver< 3 >::level_up_local_coord_of_node ( const int son_type,
Vector< double > &  s 
)

Given the son type of the element and the local coordinate s of a given node in the son element, return the local coordinate s in its father element. 3D case.

93  {
94  // If the element is unrefined between the levels the local coordinate
95  // of the node in one element is the same as that in the other element
96  // therefore we only need to perform calculations if the levels are
97  // different (i.e. son_type is not OMEGA)
98  if (son_type != Tree::OMEGA)
99  {
100  // Scale the local coordinate from the range [-1,1]x[-1,1]x[-1,1]
101  // to the range [0,1]x[0,1]x[0,1] to match the width of the local
102  // coordinate range of the fine element from the perspective of
103  // the father element. This then simply requires a shift of the
104  // coordinates to match which type of son element we're dealing with
105  s[0] = (s[0] + 1.0) / 2.0;
106  s[1] = (s[1] + 1.0) / 2.0;
107  s[2] = (s[2] + 1.0) / 2.0;
108 
109  // Cases: The son_type determines how the local coordinates should be
110  // shifted to give the local coordinates in the coarse mesh element
111  switch (son_type)
112  {
113  case OcTreeNames::LDF:
114  s[0] -= 1;
115  s[1] -= 1;
116  break;
117 
118  case OcTreeNames::LDB:
119  s[0] -= 1;
120  s[1] -= 1;
121  s[2] -= 1;
122  break;
123 
124  case OcTreeNames::LUF:
125  s[0] -= 1;
126  break;
127 
128  case OcTreeNames::LUB:
129  s[0] -= 1;
130  s[2] -= 1;
131  break;
132 
133  case OcTreeNames::RDF:
134  s[1] -= 1;
135  break;
136 
137  case OcTreeNames::RDB:
138  s[1] -= 1;
139  s[2] -= 1;
140  break;
141 
142  case OcTreeNames::RUF:
143  break;
144 
145  case OcTreeNames::RUB:
146  s[2] -= 1;
147  break;
148  }
149  } // if son_type!=Tree::OMEGA
150  } // End of level_up_local_coord_of_node
@ RDF
Definition: octree.h:54
@ RUB
Definition: octree.h:52
@ LUF
Definition: octree.h:55
@ LDF
Definition: octree.h:53
@ RDB
Definition: octree.h:50
@ LUB
Definition: octree.h:51
@ RUF
Definition: octree.h:56
@ LDB
Definition: octree.h:49

References oomph::OcTreeNames::LDB, oomph::OcTreeNames::LDF, oomph::OcTreeNames::LUB, oomph::OcTreeNames::LUF, oomph::Tree::OMEGA, oomph::OcTreeNames::RDB, oomph::OcTreeNames::RDF, oomph::OcTreeNames::RUB, oomph::OcTreeNames::RUF, and s.

◆ level_up_local_coord_of_node() [3/3]

template<unsigned DIM>
void oomph::MGSolver< DIM >::level_up_local_coord_of_node ( const int son_type,
Vector< double > &  s 
)

Given the son_type of an element and a local node number j in that element with nnode_1d nodes per coordinate direction, return the local coordinate s in its father element. Needed in the setup of the interpolation matrices

◆ max_iter()

template<unsigned DIM>
unsigned& oomph::MGSolver< DIM >::max_iter ( )
inline

Number of iterations.

603  {
604  // Return the number of V-cycles which have been done
605  return Nvcycle;
606  } // End of iterations

References oomph::MGSolver< DIM >::Nvcycle.

◆ mg_solve()

template<unsigned DIM>
void oomph::MGSolver< DIM >::mg_solve ( DoubleVector result)
protected

Linear solver.

Do the actual solve – this is called through the pure virtual solve function in the LinearSolver base class. The function is stored as protected to allow the MGPreconditioner derived class to use the solver

2526  {
2527  // If we're allowed to time things
2528  double t_mg_start = 0.0;
2530  {
2531  // Start the clock!
2532  t_mg_start = TimingHelpers::timer();
2533  }
2534 
2535  // Current level
2536  unsigned finest_level = 0;
2537 
2538  // Initialise the V-cycle counter
2539  V_cycle_counter = 0;
2540 
2541  // Calculate the norm of the residual then output
2542  double normalised_residual_norm = residual_norm(finest_level);
2544  {
2545  oomph_info << "\nResidual on finest level for V-cycle: "
2546  << normalised_residual_norm << std::endl;
2547  }
2548 
2549  // Outer loop over V-cycles
2550  //-------------------------
2551  // While the tolerance is not met and the maximum number of
2552  // V-cycles has not been completed
2553  while ((normalised_residual_norm > (this->Tolerance)) &&
2554  (V_cycle_counter != Nvcycle))
2555  {
2557  {
2558  // Output the V-cycle counter
2559  oomph_info << "\nStarting V-cycle: " << V_cycle_counter << std::endl;
2560  }
2561 
2562  // Loop downwards over all levels that have coarser levels beneath them
2563  //---------------------------------------------------------------------
2564  for (unsigned i = 0; i < Nlevel - 1; i++)
2565  {
2566  // Initialise x_mg and residual_mg to 0.0 except for the finest level
2567  // since x_mg contains the current approximation to the solution and
2568  // residual_mg contains the RHS vector on the finest level
2569  if (i != 0)
2570  {
2571  // Loop over the entries in x_mg and residual_mg
2572  X_mg_vectors_storage[i].initialise(0.0);
2573  Residual_mg_vectors_storage[i].initialise(0.0);
2574  }
2575 
2576  // Perform a few pre-smoothing steps and return vector that contains
2577  // the residuals of the linear system at this level.
2578  pre_smooth(i);
2579 
2580  // Restrict the residual to the next coarser mesh and
2581  // assign it to the RHS vector at that level
2583  } // Moving down the V-cycle
2584 
2585  // Reached the lowest level: Do a direct solve, using the RHS vector
2586  //------------------------------------------------------------------
2587  // obtained by restriction from above.
2588  //------------------------------------
2589  direct_solve();
2590 
2591  // Loop upwards over all levels that have finer levels above them
2592  //---------------------------------------------------------------
2593  for (unsigned i = Nlevel - 1; i > 0; i--)
2594  {
2595  // Interpolate solution at current level onto
2596  // next finer mesh and correct the solution x at that level
2598 
2599  // Perform a few post-smoothing steps (ignore
2600  // vector that contains the residuals of the linear system
2601  // at this level)
2602  post_smooth(i - 1);
2603  }
2604 
2605  // Calculate the new residual norm then output (if allowed)
2606  normalised_residual_norm = residual_norm(finest_level);
2607 
2608  // If required, we will document the convergence history to screen or file
2609  // (if stream open)
2611  {
2612  if (!Output_file_stream.is_open())
2613  {
2614  oomph_info << V_cycle_counter << " " << normalised_residual_norm
2615  << std::endl;
2616  }
2617  else
2618  {
2620  << normalised_residual_norm << std::endl;
2621  }
2622  } // if (Doc_convergence_history)
2623 
2624  // Set counter for number of cycles (for doc)
2625  V_cycle_counter++;
2626 
2627  // Print the residual on the finest level
2629  {
2630  oomph_info << "Residual on finest level of V-cycle: "
2631  << normalised_residual_norm << std::endl;
2632  }
2633  } // End of the V-cycles
2634 
2635  // Copy the solution into the result vector
2636  result = X_mg_vectors_storage[finest_level];
2637 
2638  // Need an extra line space if V-cycle output is suppressed
2640  {
2641  oomph_info << std::endl;
2642  }
2643 
2644  // If all output is to be suppressed
2645  if (!Suppress_all_output)
2646  {
2647  // Output number of V-cycles taken to solve
2648  if (normalised_residual_norm < (this->Tolerance))
2649  {
2650  // Indicate that the problem has been solved
2651  Has_been_solved = true;
2652  }
2653  } // if (!Suppress_all_output)
2654 
2655  // If the V-cycle output isn't suppressed
2657  {
2658  // Stop the clock
2659  double t_mg_end = TimingHelpers::timer();
2660  double total_G_setup_time = double(t_mg_end - t_mg_start);
2661  oomph_info << "CPU time for MG solver [sec]: " << total_G_setup_time
2662  << std::endl;
2663  }
2664  } // End of mg_solve
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
Vector< DoubleVector > Residual_mg_vectors_storage
Vector to store the residual vectors.
Definition: geometric_multigrid.h:688
void post_smooth(const unsigned &level)
Definition: geometric_multigrid.h:366
void restrict_residual(const unsigned &level)
Definition: geometric_multigrid.h:2020
void direct_solve()
Call the direct solver (SuperLU) to solve the problem exactly.
Definition: geometric_multigrid.h:392
void pre_smooth(const unsigned &level)
Definition: geometric_multigrid.h:348
void interpolate_and_correct(const unsigned &level)
Definition: geometric_multigrid.h:2043
double residual_norm(const unsigned &level)
Definition: geometric_multigrid.h:375

References i, oomph::oomph_info, and oomph::TimingHelpers::timer().

Referenced by oomph::MGPreconditioner< DIM >::preconditioner_solve(), and oomph::MGSolver< DIM >::solve().

◆ modify_restriction_matrices()

template<unsigned DIM>
void oomph::MGSolver< DIM >::modify_restriction_matrices
protected

Modify the restriction matrices.

Normalise the rows of the restriction matrices to avoid amplifications when projecting to the coarser level

2071  {
2072  // Create a null pointer
2073  CRDoubleMatrix* restriction_matrix_pt = 0;
2074 
2075  // Loop over the levels
2076  for (unsigned level = 0; level < Nlevel - 1; level++)
2077  {
2078  // Store a pointer to the (level)-th restriction matrix
2079  restriction_matrix_pt = Restriction_matrices_storage_pt[level];
2080 
2081  // Get access to the row start data
2082  const int* row_start_pt = restriction_matrix_pt->row_start();
2083 
2084  // Get access to the matrix entries
2085  double* value_pt = restriction_matrix_pt->value();
2086 
2087  // Initialise an auxiliary variable to store the index of the start
2088  // of the i-th row
2089  unsigned start_index = 0;
2090 
2091  // Initialise an auxiliary variable to store the index of the start
2092  // of the (i+1)-th row
2093  unsigned end_index = 0;
2094 
2095  // Store the number of rows in the matrix
2096  unsigned n_row = restriction_matrix_pt->nrow();
2097 
2098  // Loop over the rows of the matrix
2099  for (unsigned i = 0; i < n_row; i++)
2100  {
2101  // Index associated with the start of the i-th row
2102  start_index = row_start_pt[i];
2103 
2104  // Index associated with the start of the (i+1)-th row
2105  end_index = row_start_pt[i + 1];
2106 
2107  // Variable to store the sum of the absolute values of the off-diagonal
2108  // entries in the i-th row
2109  double row_sum = 0.0;
2110 
2111  // Loop over the entries in the row
2112  for (unsigned j = start_index; j < end_index; j++)
2113  {
2114  // Add the absolute value of this entry to the off-diagonal sum
2115  row_sum += value_pt[j];
2116  }
2117 
2118  // Loop over the entries in the row
2119  for (unsigned j = start_index; j < end_index; j++)
2120  {
2121  // Normalise the row entry
2122  value_pt[j] /= row_sum;
2123  }
2124  } // for (unsigned i=0;i<n_row;i++)
2125  } // for (unsigned level=0;level<Nlevel-1;level++)
2126  } // End of modify_restriction_matrices
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References i, j, oomph::CRDoubleMatrix::nrow(), oomph::CRDoubleMatrix::row_start(), and oomph::CRDoubleMatrix::value().

◆ npost_smooth()

template<unsigned DIM>
unsigned& oomph::MGSolver< DIM >::npost_smooth ( )
inline

Return the number of post-smoothing iterations (lvalue)

329  {
330  // Return the number of post-smoothing iterations to be done on each
331  // level of the hierarchy
332  return Npost_smooth;
333  } // End of npost_smooth

References oomph::MGSolver< DIM >::Npost_smooth.

◆ npre_smooth()

template<unsigned DIM>
unsigned& oomph::MGSolver< DIM >::npre_smooth ( )
inline

Return the number of pre-smoothing iterations (lvalue)

337  {
338  // Return the number of pre-smoothing iterations to be done on each
339  // level of the hierarchy
340  return Npre_smooth;
341  } // End of npre_smooth

References oomph::MGSolver< DIM >::Npre_smooth.

◆ plot()

template<unsigned DIM>
void oomph::MGSolver< DIM >::plot ( const unsigned hierarchy_level,
const DoubleVector input_vector,
const std::string &  filename 
)

Given a level in the hierarchy, an input vector and a filename this function will document the given vector according to the structure of the mesh on the given level

Plots the input vector (assuming we're dealing with scalar nodal data, otherwise I don't know how to implement this...)

2382  {
2383  // Setup an output file
2384  std::ofstream some_file;
2385  some_file.open(filename.c_str());
2386 
2387  // Set up a pointer to the refineable mesh
2388  TreeBasedRefineableMeshBase* bulk_mesh_pt =
2389  Mg_hierarchy[hierarchy_level]->mg_bulk_mesh_pt();
2390 
2391  // Find the number of elements in the bulk mesh
2392  unsigned n_el = bulk_mesh_pt->nelement();
2393 
2394  // Get the dimension of the problem (assumed to be the dimension of any
2395  // node in the mesh)
2396  unsigned n_dim = bulk_mesh_pt->node_pt(0)->ndim();
2397 
2398  // Find the number of nodes in an element
2399  unsigned nnod = bulk_mesh_pt->finite_element_pt(0)->nnode();
2400 
2401  // Find the number of nodes in an element in one direction
2402  unsigned nnod_1d = bulk_mesh_pt->finite_element_pt(0)->nnode_1d();
2403 
2404  // Loop over all elements
2405  for (unsigned e = 0; e < n_el; e++)
2406  {
2407  // Get pointer to element
2408  FiniteElement* el_pt = bulk_mesh_pt->finite_element_pt(e);
2409 
2410  // Input string for tecplot zone header (when plotting nnode_1d
2411  // points in each coordinate direction)
2412  some_file << el_pt->tecplot_zone_string(nnod_1d) << std::endl;
2413 
2414  // Loop over nodes
2415  for (unsigned j = 0; j < nnod; j++)
2416  {
2417  // Pointer to node
2418  Node* nod_pt = el_pt->node_pt(j);
2419 
2420  // Sanity check
2421  if (nod_pt->nvalue() != 1)
2422  {
2423  std::ostringstream error_stream;
2424 
2425  error_stream << "Sorry, not sure what to do here!" << nod_pt->nvalue()
2426  << std::endl;
2427 
2428  // Output the value of dimension to screen
2429  error_stream << "The dimension is: " << n_dim << std::endl;
2430 
2431  // Output the values of x_i for all i
2432  for (unsigned i = 0; i < n_dim; i++)
2433  {
2434  error_stream << nod_pt->x(i) << " ";
2435  }
2436 
2437  // End line
2438  error_stream << std::endl;
2439 
2440  // Throw an error to indicate that it was
2441  // not possible to plot the data
2442  throw OomphLibError(error_stream.str(),
2445  }
2446 
2447  // Output the coordinates of the node
2448  for (unsigned i = 0; i < n_dim; i++)
2449  {
2450  some_file << nod_pt->x(i) << " ";
2451  }
2452 
2453  // Free or pinned?
2454  int e = nod_pt->eqn_number(0);
2455  if (e >= 0)
2456  {
2457  // Output the e-th entry if the node is free
2458  some_file << input_vector[e] << std::endl;
2459  }
2460  else
2461  {
2462  // Boundary node
2463  if (nod_pt->is_on_boundary())
2464  {
2465  // On the finest level the boundary data is pinned so set to 0
2466  if (hierarchy_level == 0)
2467  {
2468  some_file << 0.0 << std::endl;
2469  }
2470  // On any other level we output this data since it corresponds
2471  // to the correction on the boundary nodes
2472  else
2473  {
2474  some_file << input_vector[e] << std::endl;
2475  }
2476  }
2477  // Hanging node
2478  else if (nod_pt->is_hanging())
2479  {
2480  // Allocate space for a double to store the weighted sum
2481  // of the surrounding master nodes of the hanging node
2482  double hang_sum = 0.0;
2483 
2484  // Find the number of master nodes of the hanging
2485  // the node in the reference element
2486  HangInfo* hang_info_pt = nod_pt->hanging_pt();
2487  unsigned nmaster = hang_info_pt->nmaster();
2488 
2489  // Loop over the master nodes
2490  for (unsigned i_master = 0; i_master < nmaster; i_master++)
2491  {
2492  // Set up a pointer to the master node
2493  Node* master_node_pt = hang_info_pt->master_node_pt(i_master);
2494 
2495  // Get the global equation number of this node
2496  int master_jj = master_node_pt->eqn_number(0);
2497 
2498  // Is the master node a proper d.o.f.?
2499  if (master_jj >= 0)
2500  {
2501  // If the weight of the master node is non-zero
2502  if (hang_info_pt->master_weight(i_master) != 0.0)
2503  {
2504  hang_sum += hang_info_pt->master_weight(i_master) *
2505  input_vector[master_jj];
2506  }
2507  } // if (master_jj>=0)
2508  } // for (unsigned i_master=0;i_master<nmaster;i_master++)
2509 
2510  // Output the weighted sum of the surrounding master nodes
2511  some_file << hang_sum << std::endl;
2512  }
2513  } // if (e>=0)
2514  } // for (unsigned j=0;j<nnod;j++)
2515  } // for (unsigned e=0;e<n_el;e++)
2516 
2517  // Close output file
2518  some_file.close();
2519  } // End of plot
Array< double, 1, 3 > e(1./3., 0.5, 2.)

References e(), oomph::Data::eqn_number(), MergeRestartFiles::filename, oomph::Mesh::finite_element_pt(), oomph::Node::hanging_pt(), i, oomph::Node::is_hanging(), oomph::Node::is_on_boundary(), j, oomph::HangInfo::master_node_pt(), oomph::HangInfo::master_weight(), oomph::Node::ndim(), oomph::Mesh::nelement(), oomph::HangInfo::nmaster(), oomph::FiniteElement::nnode(), oomph::FiniteElement::nnode_1d(), oomph::FiniteElement::node_pt(), oomph::Mesh::node_pt(), oomph::Data::nvalue(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::FiniteElement::tecplot_zone_string(), and oomph::Node::x().

◆ post_smooth()

template<unsigned DIM>
void oomph::MGSolver< DIM >::post_smooth ( const unsigned level)
inline

Post-smoother: Perform max_iter smoothing steps on the linear system Ax=b with current RHS vector, b, starting with current solution vector, x. Uses the default smoother (set in the MGProblem constructor) which can be overloaded for specific problem.

367  {
368  // Run post-smoother 'max_iter' times
369  Post_smoothers_storage_pt[level]->smoother_solve(
371  } // End of post_smooth

References oomph::MGSolver< DIM >::Post_smoothers_storage_pt, oomph::MGSolver< DIM >::Rhs_mg_vectors_storage, and oomph::MGSolver< DIM >::X_mg_vectors_storage.

◆ pre_smooth()

template<unsigned DIM>
void oomph::MGSolver< DIM >::pre_smooth ( const unsigned level)
inline

Pre-smoother: Perform 'max_iter' smoothing steps on the linear system Ax=b with current RHS vector, b, starting with current solution vector, x. Return the residual vector r=b-Ax. Uses the default smoother (set in the MGProblem constructor) which can be overloaded for a specific problem.

349  {
350  // Run pre-smoother 'max_iter' times
351  Pre_smoothers_storage_pt[level]->smoother_solve(
353 
354  // Calculate the residual r=b-Ax and assign it
355  Mg_matrices_storage_pt[level]->residual(
356  X_mg_vectors_storage[level],
357  Rhs_mg_vectors_storage[level],
359  } // End of pre_smooth

References oomph::MGSolver< DIM >::Mg_matrices_storage_pt, oomph::MGSolver< DIM >::Pre_smoothers_storage_pt, oomph::MGSolver< DIM >::Residual_mg_vectors_storage, oomph::MGSolver< DIM >::Rhs_mg_vectors_storage, and oomph::MGSolver< DIM >::X_mg_vectors_storage.

◆ residual_norm()

template<unsigned DIM>
double oomph::MGSolver< DIM >::residual_norm ( const unsigned level)
inline

Return norm of residual r=b-Ax and the residual vector itself on the level-th level

376  {
377  // And zero the entries of residual
378  Residual_mg_vectors_storage[level].initialise(0.0);
379 
380  // Get the residual
381  Mg_matrices_storage_pt[level]->residual(
382  X_mg_vectors_storage[level],
383  Rhs_mg_vectors_storage[level],
385 
386  // Return the norm of the residual
387  return Residual_mg_vectors_storage[level].norm();
388  } // End of residual_norm

References oomph::MGSolver< DIM >::Mg_matrices_storage_pt, oomph::MGSolver< DIM >::Residual_mg_vectors_storage, oomph::MGSolver< DIM >::Rhs_mg_vectors_storage, and oomph::MGSolver< DIM >::X_mg_vectors_storage.

◆ restrict_residual()

template<unsigned DIM>
void oomph::MGSolver< DIM >::restrict_residual ( const unsigned level)

Restrict residual (computed on level-th MG level) to the next coarser mesh and stick it into the coarse mesh RHS vector.

Restrict residual (computed on current MG level) to next coarser mesh and stick it into the coarse mesh RHS vector using the restriction matrix (if restrict_flag=1) or the transpose of the interpolation matrix (if restrict_flag=2)

2021  {
2022 #ifdef PARANOID
2023  // Check to make sure we can actually restrict the vector
2024  if (!(level < Nlevel - 1))
2025  {
2026  throw OomphLibError("Input exceeds the possible parameter choice.",
2029  }
2030 #endif
2031 
2032  // Multiply the residual vector by the restriction matrix on the level-th
2033  // level (to restrict the vector down to the next coarser level)
2034  Restriction_matrices_storage_pt[level]->multiply(
2036  } // End of restrict_residual

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ restriction_self_test()

template<unsigned DIM>
void oomph::MGSolver< DIM >::restriction_self_test

Make a self-test to make sure that the interpolation matrices are doing the same thing to restrict the vectors down through the heirachy.

Function which implements a self-test to restrict the residual vector down all of the coarser grids and output the restricted vectors to file

2308  {
2309  // Set the start of the output file name. The full names will
2310  // set after we calculate the restricted vectors
2311  std::string outputfile = "RESLT/restriction_self_test";
2312 
2313  // Loop over the levels of the hierarchy
2314  for (unsigned level = 0; level < Nlevel - 1; level++)
2315  {
2316  // Restrict the vector down to the next level
2317  Restriction_matrices_storage_pt[level]->multiply(
2320  } // End of the for loop over the hierarchy levels
2321 
2322  // Loop over the levels of hierarchy to plot the restricted vectors
2323  for (unsigned level = 0; level < Nlevel; level++)
2324  {
2325  // Set output file name
2326  std::string filename = outputfile;
2327  std::stringstream string;
2328  string << level;
2329  filename += string.str();
2330  filename += ".dat";
2331 
2332  // Plot the RHS vector on the current level
2334 
2335  } // End of for-loop to output the RHS vector on each level
2336  } // End of restriction_self_test
Vector< DoubleVector > Restriction_self_test_vectors_storage
Definition: geometric_multigrid.h:698

References MergeRestartFiles::filename, PlanarWave::plot(), and oomph::Global_string_for_annotation::string().

◆ self_test()

template<unsigned DIM>
void oomph::MGSolver< DIM >::self_test

Makes a vector, restricts it down the levels of the hierarchy and documents it at each level. After this is done the vector is interpolated up the levels of the hierarchy with the output being documented at each level

2136  {
2137  // Start the timer
2138  double t_st_start = TimingHelpers::timer();
2139 
2140  // Notify user that the hierarchy of levels is complete
2141  oomph_info << "\nStarting the multigrid solver self-test." << std::endl;
2142 
2143  // Resize the vector storing all of the restricted vectors
2145 
2146  // Resize the vector storing all of the interpolated vectors
2148 
2149  // Find the number of dofs on the finest level
2150  unsigned n_dof = X_mg_vectors_storage[0].nrow();
2151 
2152  // Need to set up the distribution of the finest level vector
2153  LinearAlgebraDistribution* dist_pt = new LinearAlgebraDistribution(
2154  Mg_problem_pt->communicator_pt(), n_dof, false);
2155 
2156 #ifdef PARANOID
2157 #ifdef OOMPH_HAS_MPI
2158  // Set up the warning messages
2159  std::string warning_message = "Setup of distribution has not been ";
2160  warning_message += "tested with MPI.";
2161 
2162  // If we're not running the code in serial
2163  if (dist_pt->communicator_pt()->nproc() > 1)
2164  {
2165  // Throw a warning
2166  OomphLibWarning(
2168  }
2169 #endif
2170 #endif
2171 
2172  // Build the vector using the distribution of the restriction matrix
2173  Restriction_self_test_vectors_storage[0].build(dist_pt);
2174 
2175  // Delete the distribution pointer
2176  delete dist_pt;
2177 
2178  // Make it a null pointer
2179  dist_pt = 0;
2180 
2181  // Now assign the values to the first vector. This will be restricted down
2182  // the levels of the hierarchy then back up
2184 
2185  // Call the restriction self-test
2187 
2188  // Set the coarest level vector in Restriction_self_test_vectors_storage
2189  // to be the last entry in Interpolation_self_test_vectors_storage. This
2190  // will be interpolated up to the finest level in interpolation_self_test()
2193 
2194  // Call the interpolation self-test
2196 
2197  // Destroy all of the created restriction self-test vectors
2199 
2200  // Destroy all of the created interpolation self-test vectors
2202 
2203  // Stop the clock
2204  double t_st_end = TimingHelpers::timer();
2205  double total_st_time = double(t_st_end - t_st_start);
2206  oomph_info << "\nCPU time for self-test [sec]: " << total_st_time
2207  << std::endl;
2208 
2209  // Notify user that the hierarchy of levels is complete
2210  oomph_info << "\n====================Self-Test Complete===================="
2211  << std::endl;
2212  } // End of self_test
void set_self_test_vector()
Definition: geometric_multigrid.h:2219
void interpolation_self_test()
Definition: geometric_multigrid.h:2344
void restriction_self_test()
Definition: geometric_multigrid.h:2307
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition: problem.h:1246

References oomph::LinearAlgebraDistribution::communicator_pt(), oomph::OomphCommunicator::nproc(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::Global_string_for_annotation::string(), and oomph::TimingHelpers::timer().

◆ set_post_smoother_factory_function()

template<unsigned DIM>
void oomph::MGSolver< DIM >::set_post_smoother_factory_function ( PostSmootherFactoryFctPt  post_smoother_fn)
inline

Access function to set the post-smoother creation function.

111  {
112  // Assign the function pointer
113  Post_smoother_factory_function_pt = post_smoother_fn;
114  }

References oomph::MGSolver< DIM >::Post_smoother_factory_function_pt.

Referenced by FluxPoissonMGProblem< ELEMENT, MESH >::set_multigrid_solver(), and UnitCubePoissonMGProblem< ELEMENT, MESH >::set_multigrid_solver().

◆ set_pre_smoother_factory_function()

template<unsigned DIM>
void oomph::MGSolver< DIM >::set_pre_smoother_factory_function ( PreSmootherFactoryFctPt  pre_smoother_fn)
inline

Access function to set the pre-smoother creation function.

103  {
104  // Assign the function pointer
105  Pre_smoother_factory_function_pt = pre_smoother_fn;
106  }

References oomph::MGSolver< DIM >::Pre_smoother_factory_function_pt.

Referenced by FluxPoissonMGProblem< ELEMENT, MESH >::set_multigrid_solver(), and UnitCubePoissonMGProblem< ELEMENT, MESH >::set_multigrid_solver().

◆ set_restriction_matrices_as_interpolation_transposes()

template<unsigned DIM>
void oomph::MGSolver< DIM >::set_restriction_matrices_as_interpolation_transposes ( )
inline

Builds a CRDoubleMatrix on each level that is used to restrict the residual between levels. The transpose can be used as the interpolation matrix

466  {
467  for (unsigned i = 0; i < Nlevel - 1; i++)
468  {
469  // Dynamically allocate the restriction matrix
470  Restriction_matrices_storage_pt[i] = new CRDoubleMatrix;
471 
472  // Set the restriction matrix to be the transpose of the
473  // interpolation matrix
474  Interpolation_matrices_storage_pt[i]->get_matrix_transpose(
476  }
477  } // End of set_restriction_matrices_as_interpolation_transposes

References i, oomph::MGSolver< DIM >::Interpolation_matrices_storage_pt, oomph::MGSolver< DIM >::Nlevel, and oomph::MGSolver< DIM >::Restriction_matrices_storage_pt.

◆ set_self_test_vector()

template<unsigned DIM>
void oomph::MGSolver< DIM >::set_self_test_vector

Makes a vector which will be used in the self-test. Is currently set to make the entries of the vector represent a plane wave propagating at an angle of 45 degrees

Sets the initial vector to be used in the restriction and interpolation self-tests

2220  {
2221  // Set up a pointer to the refineable mesh
2222  TreeBasedRefineableMeshBase* bulk_mesh_pt =
2224 
2225  // Find the number of elements in the bulk mesh
2226  unsigned n_el = bulk_mesh_pt->nelement();
2227 
2228  // Get the dimension of the problem (assumed to be the dimension of any
2229  // node in the mesh)
2230  unsigned n_dim = bulk_mesh_pt->node_pt(0)->ndim();
2231 
2232  // Find the number of nodes in an element
2233  unsigned nnod = bulk_mesh_pt->finite_element_pt(0)->nnode();
2234 
2235  // Loop over all elements
2236  for (unsigned e = 0; e < n_el; e++)
2237  {
2238  // Get pointer to element
2239  FiniteElement* el_pt = bulk_mesh_pt->finite_element_pt(e);
2240 
2241  // Loop over nodes
2242  for (unsigned j = 0; j < nnod; j++)
2243  {
2244  // Pointer to node
2245  Node* nod_pt = el_pt->node_pt(j);
2246 
2247  // Sanity check
2248  if (nod_pt->nvalue() != 1)
2249  {
2250  // Set up an output stream
2251  std::ostringstream error_stream;
2252 
2253  // Output the error message
2254  error_stream << "Sorry, not sure what to do here! I can't deal with "
2255  << nod_pt->nvalue() << " values!" << std::endl;
2256 
2257  // Throw an error to indicate that it was not possible to plot the
2258  // data
2259  throw OomphLibError(error_stream.str(),
2262  }
2263 
2264  // Free or pinned?
2265  int eqn_num = nod_pt->eqn_number(0);
2266 
2267  // If it's a free node
2268  if (eqn_num >= 0)
2269  {
2270  // Initialise the variable coordinate_sum
2271  double coordinate_sum = 0.0;
2272 
2273  // Loop over the coordinates of the node
2274  for (unsigned i = 0; i < n_dim; i++)
2275  {
2276  // Increment coordinate_sum by the value of x(i)
2277  coordinate_sum += nod_pt->x(i);
2278  }
2279 
2280  // Store the value of pi in cache
2281  double pi = MathematicalConstants::Pi;
2282 
2283  // Make the vector represent a constant function
2285  sin(pi * (nod_pt->x(0))) * sin(pi * (nod_pt->x(1)));
2286  }
2287  } // for (unsigned j=0;j<nnod;j++)
2288  } // for (unsigned e=0;e<n_el;e++)
2289 
2290  // // Get the size of the vector
2291  // unsigned n_row=Restriction_self_test_vectors_storage[0].nrow();
2292 
2293  // // Loop over the entries of the vector
2294  // for (unsigned i=0;i<n_row;i++)
2295  // {
2296  // // Make the vector represent a constant function
2297  // Restriction_self_test_vectors_storage[0][i]=1.0;
2298  // }
2299  } // End of set_self_test_vector
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
const Mdouble pi
Definition: ExtendedMath.h:23
const double Pi
50 digits from maple
Definition: oomph_utilities.h:157

References e(), oomph::Data::eqn_number(), oomph::Mesh::finite_element_pt(), i, j, oomph::Node::ndim(), oomph::Mesh::nelement(), oomph::FiniteElement::nnode(), oomph::FiniteElement::node_pt(), oomph::Mesh::node_pt(), oomph::Data::nvalue(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, constants::pi, oomph::MathematicalConstants::Pi, sin(), and oomph::Node::x().

◆ setup_interpolation_matrices()

template<unsigned DIM>
void oomph::MGSolver< DIM >::setup_interpolation_matrices

Setup the interpolation matrix on each level.

Setup the interpolation matrices.

1511  {
1512  // Variable to hold the number of sons in an element
1513  unsigned n_sons;
1514 
1515  // Number of son elements
1516  if (DIM == 2)
1517  {
1518  n_sons = 4;
1519  }
1520  else if (DIM == 3)
1521  {
1522  n_sons = 8;
1523  }
1524  else
1525  {
1526  std::ostringstream error_message_stream;
1527  error_message_stream << "DIM should be 2 or 3 not " << DIM << std::endl;
1528  throw OomphLibError(error_message_stream.str(),
1531  }
1532 
1533  // Vector of local coordinates in the element
1534  Vector<double> s(DIM, 0.0);
1535 
1536  // Loop over each level (apart from the coarsest level; an interpolation
1537  // matrix and thus a restriction matrix is not needed here), with 0 being
1538  // the finest level and Nlevel-1 being the coarsest level
1539  for (unsigned level = 0; level < Nlevel - 1; level++)
1540  {
1541  // Assign values to a couple of variables to help out
1542  unsigned coarse_level = level + 1;
1543  unsigned fine_level = level;
1544 
1545  // Make a pointer to the mesh on the finer level and dynamic_cast
1546  // it as an object of the refineable mesh class
1547  RefineableMeshBase* ref_fine_mesh_pt = dynamic_cast<RefineableMeshBase*>(
1548  Mg_hierarchy[fine_level]->mg_bulk_mesh_pt());
1549 
1550  // Make a pointer to the mesh on the coarse level and dynamic_cast
1551  // it as an object of the refineable mesh class
1552  RefineableMeshBase* ref_coarse_mesh_pt =
1553  dynamic_cast<RefineableMeshBase*>(
1554  Mg_hierarchy[coarse_level]->mg_bulk_mesh_pt());
1555 
1556  // Access information about the number of elements in the fine mesh
1557  // from the pointer to the fine mesh (to loop over the rows of the
1558  // interpolation matrix)
1559  unsigned fine_n_element = ref_fine_mesh_pt->nelement();
1560 
1561  // The numbers of rows and columns in the interpolation matrix. The
1562  // number of unknowns has been divided by 2 since there are 2 dofs at
1563  // each node in the mesh corresponding to the real and imaginary part
1564  // of the solution
1565  unsigned n_rows = Mg_hierarchy[fine_level]->ndof();
1566  unsigned n_cols = Mg_hierarchy[coarse_level]->ndof();
1567 
1568  // Mapping relating the pointers to related elements in the coarse and
1569  // fine meshes: coarse_mesh_element_pt[fine_mesh_element_pt]
1570  // If the element in the fine mesh has been unrefined between these two
1571  // levels, this map returns the father element in the coarsened mesh.
1572  // If this element in the fine mesh has not been unrefined,
1573  // the map returns the pointer to the same-sized equivalent
1574  // element in the coarsened mesh.
1575  std::map<RefineableQElement<DIM>*, RefineableQElement<DIM>*>
1576  coarse_mesh_reference_element_pt;
1577 
1578  // Counter of elements in coarse and fine meshes: Start with element
1579  // zero in both meshes.
1580  unsigned e_coarse = 0;
1581  unsigned e_fine = 0;
1582 
1583  // While loop over fine elements (while because we're
1584  // incrementing the counter internally if the element was
1585  // unrefined...)
1586  while (e_fine < fine_n_element)
1587  {
1588  // Pointer to element in fine mesh
1589  RefineableQElement<DIM>* el_fine_pt =
1590  dynamic_cast<RefineableQElement<DIM>*>(
1591  ref_fine_mesh_pt->finite_element_pt(e_fine));
1592 
1593  // Pointer to element in coarse mesh
1594  RefineableQElement<DIM>* el_coarse_pt =
1595  dynamic_cast<RefineableQElement<DIM>*>(
1596  ref_coarse_mesh_pt->finite_element_pt(e_coarse));
1597 
1598  // If the levels are different then the element in the fine
1599  // mesh has been unrefined between these two levels
1600  if (el_fine_pt->tree_pt()->level() != el_coarse_pt->tree_pt()->level())
1601  {
1602  // The element in the fine mesh has been unrefined between these two
1603  // levels. Hence it and its three brothers (ASSUMED to be stored
1604  // consecutively in the Mesh's vector of pointers to its constituent
1605  // elements -- we'll check this!) share the same father element in
1606  // the coarse mesh, currently pointed to by el_coarse_pt.
1607  for (unsigned i = 0; i < n_sons; i++)
1608  {
1609  // Set mapping to father element in coarse mesh
1610  coarse_mesh_reference_element_pt
1611  [dynamic_cast<RefineableQElement<DIM>*>(
1612  ref_fine_mesh_pt->finite_element_pt(e_fine))] = el_coarse_pt;
1613 
1614  // Increment counter for elements in fine mesh
1615  e_fine++;
1616  }
1617  }
1618  // The element in the fine mesh has not been unrefined between
1619  // these two levels, so the reference element is the same-sized
1620  // equivalent element in the coarse mesh
1621  else
1622  {
1623  // Set the mapping between the two elements since they are
1624  // the same element
1625  coarse_mesh_reference_element_pt[el_fine_pt] = el_coarse_pt;
1626 
1627  // Increment counter for elements in fine mesh
1628  e_fine++;
1629  }
1630  // Increment counter for elements in coarse mesh
1631  e_coarse++;
1632  } // End of while loop for setting up element-coincidences
1633 
1634  // To allow update of a row only once we use stl vectors for bools
1635  std::vector<bool> contribution_made(n_rows, false);
1636 
1637  // Make storage vectors to form the interpolation matrix using a
1638  // condensed row matrix (CRDoubleMatrix). The i-th value of the vector
1639  // row_start contains entries which tells us at which entry of the
1640  // vector column_start we start on the i-th row of the actual matrix.
1641  // The entries of column_start indicate the column position of each
1642  // non-zero entry in every row. This runs through the first row
1643  // from left to right then the second row (again, left to right)
1644  // and so on until the end. The entries in value are the entries in
1645  // the interpolation matrix. The vector column_start has the same length
1646  // as the vector value.
1647  Vector<double> value;
1648  Vector<int> column_index;
1649  Vector<int> row_start(n_rows + 1);
1650 
1651  // The value of index will tell us which row of the interpolation matrix
1652  // we're working on in the following for loop
1653  unsigned index = 0;
1654 
1655  // New loop to go over each element in the fine mesh
1656  for (unsigned k = 0; k < fine_n_element; k++)
1657  {
1658  // Set a pointer to the element in the fine mesh
1659  RefineableQElement<DIM>* el_fine_pt =
1660  dynamic_cast<RefineableQElement<DIM>*>(
1661  ref_fine_mesh_pt->finite_element_pt(k));
1662 
1663  // Get the reference element (either the father element or the
1664  // same-sized element) in the coarse mesh
1665  RefineableQElement<DIM>* el_coarse_pt =
1666  coarse_mesh_reference_element_pt[el_fine_pt];
1667 
1668  // Find out what type of son it is (set to OMEGA if no unrefinement
1669  // took place)
1670  int son_type = 0;
1671 
1672  // Check if the elements are different on both levels (i.e. to check
1673  // if any unrefinement took place)
1674  if (el_fine_pt->tree_pt()->level() != el_coarse_pt->tree_pt()->level())
1675  {
1676  // If there was refinement we need to find the son type
1677  son_type = el_fine_pt->tree_pt()->son_type();
1678  }
1679  else
1680  {
1681  // If there was no refinement then the son_type is given by the
1682  // value of Tree::OMEGA
1683  son_type = Tree::OMEGA;
1684  }
1685 
1686  // Find the number of nodes in the fine mesh element
1687  unsigned nnod_fine = el_fine_pt->nnode();
1688 
1689  // Loop through all the nodes in an element in the fine mesh
1690  for (unsigned i = 0; i < nnod_fine; i++)
1691  {
1692  // Row number in interpolation matrix: Global equation number
1693  // of the d.o.f. stored at this node in the fine element
1694  int ii = el_fine_pt->node_pt(i)->eqn_number(0);
1695 
1696  // Check whether or not the node is a proper d.o.f.
1697  if (ii >= 0)
1698  {
1699  // Only assign values to the given row of the interpolation
1700  // matrix if they haven't already been assigned
1701  if (contribution_made[ii] == false)
1702  {
1703  // The value of index was initialised when we allocated space
1704  // for the three vectors to store the CRDoubleMatrix. We use
1705  // index to go through the entries of the row_start vector.
1706  // The next row starts at the value.size() (draw out the entries
1707  // in value if this doesn't make sense noting that the storage
1708  // for the vector 'value' is dynamically allocated)
1709  row_start[index] = value.size();
1710 
1711  // Calculate the local coordinates of the given node
1712  el_fine_pt->local_coordinate_of_node(i, s);
1713 
1714  // Find the local coordinates s, of the present node, in the
1715  // reference element in the coarse mesh, given the element's
1716  // son_type (e.g. SW,SE... )
1717  level_up_local_coord_of_node(son_type, s);
1718 
1719  // Allocate space for shape functions in the coarse mesh
1720  Shape psi(el_coarse_pt->nnode());
1721 
1722  // Set the shape function in the reference element
1723  el_coarse_pt->shape(s, psi);
1724 
1725  // Auxiliary storage
1726  std::map<unsigned, double> contribution;
1727  Vector<unsigned> keys;
1728 
1729  // Find the number of nodes in an element in the coarse mesh
1730  unsigned nnod_coarse = el_coarse_pt->nnode();
1731 
1732  // Loop through all the nodes in the reference element
1733  for (unsigned j = 0; j < nnod_coarse; j++)
1734  {
1735  // Column number in interpolation matrix: Global equation
1736  // number of the d.o.f. stored at this node in the coarse
1737  // element
1738  int jj = el_coarse_pt->node_pt(j)->eqn_number(0);
1739 
1740  // If the value stored at this node is pinned or hanging
1741  if (jj < 0)
1742  {
1743  // Hanging node: In this case we need to accumulate the
1744  // contributions from the master nodes
1745  if (el_coarse_pt->node_pt(j)->is_hanging())
1746  {
1747  // Find the number of master nodes of the hanging
1748  // the node in the reference element
1749  HangInfo* hang_info_pt =
1750  el_coarse_pt->node_pt(j)->hanging_pt();
1751  unsigned nmaster = hang_info_pt->nmaster();
1752 
1753  // Loop over the master nodes
1754  for (unsigned i_master = 0; i_master < nmaster; i_master++)
1755  {
1756  // Set up a pointer to the master node
1757  Node* master_node_pt =
1758  hang_info_pt->master_node_pt(i_master);
1759 
1760  // The column number in the interpolation matrix: the
1761  // global equation number of the d.o.f. stored at this
1762  // master node for the coarse element
1763  int master_jj = master_node_pt->eqn_number(0);
1764 
1765  // Is the master node a proper d.o.f.?
1766  if (master_jj >= 0)
1767  {
1768  // If the weight of the master node is non-zero
1769  if (psi(j) * hang_info_pt->master_weight(i_master) !=
1770  0.0)
1771  {
1772  contribution[master_jj] +=
1773  psi(j) * hang_info_pt->master_weight(i_master);
1774  }
1775  } // if (master_jj>=0)
1776  } // for (unsigned i_master=0;i_master<nmaster;i_master++)
1777  } // if (el_coarse_pt->node_pt(j)->is_hanging())
1778  }
1779  // In the case that the node is not pinned or hanging
1780  else
1781  {
1782  // If we can get a nonzero contribution from the shape
1783  // function
1784  if (psi(j) != 0.0)
1785  {
1786  contribution[jj] += psi(j);
1787  }
1788  } // if (jj<0) else
1789  } // for (unsigned j=0;j<nnod_coarse;j++)
1790 
1791  // Put the contributions into the value vector
1792  for (std::map<unsigned, double>::iterator it =
1793  contribution.begin();
1794  it != contribution.end();
1795  ++it)
1796  {
1797  if (it->second != 0)
1798  {
1799  column_index.push_back(it->first);
1800  value.push_back(it->second);
1801  }
1802  } // for (std::map<unsigned,double>::iterator it=...)
1803 
1804  // Increment the value of index by 1 to indicate that we have
1805  // finished the row, or equivalently, covered another global
1806  // node in the fine mesh
1807  index++;
1808 
1809  // Change the entry in contribution_made to true now to indicate
1810  // that the row has been filled
1811  contribution_made[ii] = true;
1812  } // if(contribution_made[ii]==false)
1813  } // if (ii>=0)
1814  } // for(unsigned i=0;i<nnod_element;i++)
1815  } // for (unsigned k=0;k<fine_n_element;k++)
1816 
1817  // Set the last entry in the row_start vector
1818  row_start[n_rows] = value.size();
1819 
1820  // Set the interpolation matrix to be that formed as the CRDoubleMatrix
1821  // using the vectors value, row_start, column_index and the value
1822  // of fine_n_unknowns and coarse_n_unknowns
1824  level, value, column_index, row_start, n_cols, n_rows);
1825  } // for (unsigned level=0;level<Nlevel-1;level++)
1826  } // End of setup_interpolation_matrices
void level_up_local_coord_of_node(const int &son_type, Vector< double > &s)
void interpolation_matrix_set(const unsigned &level, double *value, int *col_index, int *row_st, unsigned &ncol, unsigned &nnz)
Definition: geometric_multigrid.h:402
char char char int int * k
Definition: level2_impl.h:374

References DIM, oomph::Data::eqn_number(), oomph::Mesh::finite_element_pt(), i, j, k, oomph::HangInfo::master_node_pt(), oomph::HangInfo::master_weight(), oomph::Mesh::nelement(), oomph::HangInfo::nmaster(), oomph::Tree::OMEGA, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, s, and Eigen::value.

◆ setup_interpolation_matrices_unstructured()

template<unsigned DIM>
void oomph::MGSolver< DIM >::setup_interpolation_matrices_unstructured

Setup the interpolation matrices.

Setup the interpolation matrix on each level (used for unstructured meshes)

1833  {
1834  // Vector of local coordinates in the element
1835  Vector<double> s(DIM, 0.0);
1836 
1837  // Loop over each level (apart from the coarsest level; an interpolation
1838  // matrix and thus a restriction matrix is not needed here), with 0 being
1839  // the finest level and Nlevel-1 being the coarsest level
1840  for (unsigned level = 0; level < Nlevel - 1; level++)
1841  {
1842  // Assign values to a couple of variables to help out
1843  unsigned coarse_level = level + 1;
1844  unsigned fine_level = level;
1845 
1846  // Make a pointer to the mesh on the finer level and dynamic_cast
1847  // it as an object of the refineable mesh class
1848  Mesh* ref_fine_mesh_pt = Mg_hierarchy[fine_level]->mg_bulk_mesh_pt();
1849 
1850  // To use the locate zeta functionality the coarse mesh must be of the
1851  // type MeshAsGeomObject
1852  MeshAsGeomObject* coarse_mesh_from_obj_pt =
1853  new MeshAsGeomObject(Mg_hierarchy[coarse_level]->mg_bulk_mesh_pt());
1854 
1855  // Access information about the number of degrees of freedom
1856  // from the pointers to the problem on each level
1857  unsigned coarse_n_unknowns = Mg_hierarchy[coarse_level]->ndof();
1858  unsigned fine_n_unknowns = Mg_hierarchy[fine_level]->ndof();
1859 
1860  // Make storage vectors to form the interpolation matrix using a
1861  // condensed row matrix (CRDoubleMatrix). The i-th value of the vector
1862  // row_start contains entries which tells us at which entry of the
1863  // vector column_start we start on the i-th row of the actual matrix.
1864  // The entries of column_start indicate the column position of each
1865  // non-zero entry in every row. This runs through the first row
1866  // from left to right then the second row (again, left to right)
1867  // and so on until the end. The entries in value are the entries in
1868  // the interpolation matrix. The vector column_start has the same length
1869  // as the vector value.
1870  Vector<double> value;
1871  Vector<int> column_index;
1872  Vector<int> row_start(fine_n_unknowns + 1);
1873 
1874  // Vector to contain the (Eulerian) spatial location of the fine node
1875  Vector<double> fine_node_position(DIM);
1876 
1877  // Find the number of nodes in the mesh
1878  unsigned n_node_fine_mesh = ref_fine_mesh_pt->nnode();
1879 
1880  // Loop over the unknowns in the mesh
1881  for (unsigned i_fine_node = 0; i_fine_node < n_node_fine_mesh;
1882  i_fine_node++)
1883  {
1884  // Set a pointer to the i_fine_unknown-th node in the fine mesh
1885  Node* fine_node_pt = ref_fine_mesh_pt->node_pt(i_fine_node);
1886 
1887  // Get the global equation number
1888  int i_fine = fine_node_pt->eqn_number(0);
1889 
1890  // If the node is a proper d.o.f.
1891  if (i_fine >= 0)
1892  {
1893  // Row number in interpolation matrix: Global equation number
1894  // of the d.o.f. stored at this node in the fine element
1895  row_start[i_fine] = value.size();
1896 
1897  // Get the (Eulerian) spatial location of the fine node
1898  fine_node_pt->position(fine_node_position);
1899 
1900  // Create a null pointer to the GeomObject class
1901  GeomObject* el_pt = 0;
1902 
1903  // Get the reference element (either the father element or the
1904  // same-sized element) in the coarse mesh using locate_zeta
1905  coarse_mesh_from_obj_pt->locate_zeta(fine_node_position, el_pt, s);
1906 
1907  // Upcast GeomElement as a FiniteElement
1908  FiniteElement* el_coarse_pt = dynamic_cast<FiniteElement*>(el_pt);
1909 
1910  // Find the number of nodes in the element
1911  unsigned n_node = el_coarse_pt->nnode();
1912 
1913  // Allocate space for shape functions in the coarse mesh
1914  Shape psi(n_node);
1915 
1916  // Calculate the geometric shape functions at local coordinate s
1917  el_coarse_pt->shape(s, psi);
1918 
1919  // Auxiliary storage
1920  std::map<unsigned, double> contribution;
1921  Vector<unsigned> keys;
1922 
1923  // Loop through all the nodes in the (coarse mesh) element containing
1924  // the node pointed to by fine_node_pt (fine mesh)
1925  for (unsigned j_node = 0; j_node < n_node; j_node++)
1926  {
1927  // Get the j_coarse_unknown-th node in the coarse element
1928  Node* coarse_node_pt = el_coarse_pt->node_pt(j_node);
1929 
1930  // Column number in interpolation matrix: Global equation number of
1931  // the d.o.f. stored at this node in the coarse element
1932  int j_coarse = coarse_node_pt->eqn_number(0);
1933 
1934  // If the value stored at this node is pinned or hanging
1935  if (j_coarse < 0)
1936  {
1937  // Hanging node: In this case we need to accumulate the
1938  // contributions from the master nodes
1939  if (el_coarse_pt->node_pt(j_node)->is_hanging())
1940  {
1941  // Find the number of master nodes of the hanging
1942  // the node in the reference element
1943  HangInfo* hang_info_pt = coarse_node_pt->hanging_pt();
1944  unsigned nmaster = hang_info_pt->nmaster();
1945 
1946  // Loop over the master nodes
1947  for (unsigned i_master = 0; i_master < nmaster; i_master++)
1948  {
1949  // Set up a pointer to the master node
1950  Node* master_node_pt = hang_info_pt->master_node_pt(i_master);
1951 
1952  // The column number in the interpolation matrix: the
1953  // global equation number of the d.o.f. stored at this master
1954  // node for the coarse element
1955  int master_jj = master_node_pt->eqn_number(0);
1956 
1957  // Is the master node a proper d.o.f.?
1958  if (master_jj >= 0)
1959  {
1960  // If the weight of the master node is non-zero
1961  if (psi(j_node) * hang_info_pt->master_weight(i_master) !=
1962  0.0)
1963  {
1964  contribution[master_jj] +=
1965  psi(j_node) * hang_info_pt->master_weight(i_master);
1966  }
1967  } // End of if statement (check it's not a boundary node)
1968  } // End of the loop over the master nodes
1969  } // End of the if statement for only hanging nodes
1970  } // End of the if statement for pinned or hanging nodes
1971  // In the case that the node is not pinned or hanging
1972  else
1973  {
1974  // If we can get a nonzero contribution from the shape function
1975  // at the j_node-th node in the element
1976  if (psi(j_node) != 0.0)
1977  {
1978  contribution[j_coarse] += psi(j_node);
1979  }
1980  } // End of the if-else statement (check if the node was
1981  // pinned/hanging)
1982  } // Finished loop over the nodes j in the reference element (coarse)
1983 
1984  // Put the contributions into the value vector
1985  for (std::map<unsigned, double>::iterator it = contribution.begin();
1986  it != contribution.end();
1987  ++it)
1988  {
1989  if (it->second != 0)
1990  {
1991  value.push_back(it->second);
1992  column_index.push_back(it->first);
1993  }
1994  } // End of putting contributions into the value vector
1995  } // End check (whether or not the fine node was a d.o.f.)
1996  } // End of the for-loop over nodes in the fine mesh
1997 
1998  // Set the last entry of row_start
1999  row_start[fine_n_unknowns] = value.size();
2000 
2001  // Set the interpolation matrix to be that formed as the CRDoubleMatrix
2002  // using the vectors value, row_start, column_index and the value
2003  // of fine_n_unknowns and coarse_n_unknowns
2005  value,
2006  column_index,
2007  row_start,
2008  coarse_n_unknowns,
2009  fine_n_unknowns);
2010  } // End of loop over each level
2011  } // End of setup_interpolation_matrices_unstructured

References DIM, oomph::Data::eqn_number(), oomph::Node::hanging_pt(), oomph::Node::is_hanging(), oomph::MeshAsGeomObject::locate_zeta(), oomph::HangInfo::master_node_pt(), oomph::HangInfo::master_weight(), oomph::HangInfo::nmaster(), oomph::FiniteElement::nnode(), oomph::Mesh::nnode(), oomph::FiniteElement::node_pt(), oomph::Mesh::node_pt(), oomph::Node::position(), s, oomph::FiniteElement::shape(), and Eigen::value.

◆ setup_mg_hierarchy()

template<unsigned DIM>
void oomph::MGSolver< DIM >::setup_mg_hierarchy
private

Set up the MG hierarchy.

Function to set up the hierachy of levels. Creates a vector of pointers to each MG level

969  {
970  // Initialise the timer start variable
971  double t_m_start = 0.0;
972 
973  // Notify the user if it is allowed
974  if (!Suppress_all_output)
975  {
976  // Notify user of progress
977  oomph_info
978  << "\n===============Creating Multigrid Hierarchy==============="
979  << std::endl;
980 
981  // Start clock
982  t_m_start = TimingHelpers::timer();
983  }
984 
985  // Create a bool to indicate whether or not we could create an unrefined
986  // copy. This bool will be assigned the value FALSE when the current copy
987  // is the last level of the multigrid hierarchy
988  bool managed_to_create_unrefined_copy = true;
989 
990  // Now keep making copies and try to make an unrefined copy of
991  // the mesh
992  unsigned level = 0;
993 
994  // Set up all of the levels by making a completely unrefined copy
995  // of the problem using the function make_new_problem
996  while (managed_to_create_unrefined_copy)
997  {
998  // Make a new object of the same type as the derived problem
999  MGProblem* new_problem_pt = Mg_problem_pt->make_new_problem();
1000 
1001  // Do anything that needs to be done before we can refine the mesh
1002  new_problem_pt->actions_before_adapt();
1003 
1004  // To create the next level in the hierarchy we need to create a mesh
1005  // which matches the refinement of the current problem and then unrefine
1006  // the mesh. This can alternatively be done using the function
1007  // refine_base_mesh_as_in_reference_mesh_minus_one which takes a
1008  // reference mesh to do precisely the above with
1009  managed_to_create_unrefined_copy =
1010  new_problem_pt->mg_bulk_mesh_pt()
1011  ->refine_base_mesh_as_in_reference_mesh_minus_one(
1012  Mg_hierarchy[level]->mg_bulk_mesh_pt());
1013 
1014  // If we were able to unrefine the problem on the current level
1015  // then add the unrefined problem to a vector of the levels
1016  if (managed_to_create_unrefined_copy)
1017  {
1018  // Another level has been created so increment the level counter
1019  level++;
1020 
1021  // If the documentation of everything has not been suppressed
1022  // then tell the user we managed to create another level
1023  if (!Suppress_all_output)
1024  {
1025  // Notify user that unrefinement was successful
1026  oomph_info << "\nSuccess! Level " << level << " has been created."
1027  << std::endl;
1028  }
1029 
1030  // Do anything that needs to be done after refinement
1031  new_problem_pt->actions_after_adapt();
1032 
1033  // Do the equation numbering for the new problem
1034  oomph_info << "\n - Number of equations: "
1035  << new_problem_pt->assign_eqn_numbers() << std::endl;
1036 
1037  // Add the new problem pointer onto the vector of MG levels
1038  // and increment the value of level by 1
1039  Mg_hierarchy.push_back(new_problem_pt);
1040  }
1041  // If we weren't able to create an unrefined copy
1042  else
1043  {
1044  // Delete the new problem
1045  delete new_problem_pt;
1046 
1047  // Make it a null pointer
1048  new_problem_pt = 0;
1049 
1050  // Assign the number of levels to Nlevel
1051  Nlevel = Mg_hierarchy.size();
1052 
1053  // If we're allowed to document then tell the user we've reached
1054  // the coarsest level of the hierarchy
1055  if (!Suppress_all_output)
1056  {
1057  // Notify the user
1058  oomph_info << "\n Reached the coarsest level! "
1059  << "Number of levels: " << Nlevel << std::endl;
1060  }
1061  } // if (managed_to_unrefine)
1062  } // while (managed_to_unrefine)
1063 
1064  // Given that we know the number of levels in the hierarchy we can resize
1065  // the vectors which will store all the information required for our solver:
1066  // Resize the vector storing all of the system matrices
1067  Mg_matrices_storage_pt.resize(Nlevel, 0);
1068 
1069  // Resize the vector storing all of the solution vectors (X_mg)
1070  X_mg_vectors_storage.resize(Nlevel);
1071 
1072  // Resize the vector storing all of the RHS vectors (Rhs_mg)
1074 
1075  // Resize the vector storing all of the residual vectors
1077 
1078  // Allocate space for the pre-smoother storage vector (remember, we do
1079  // not need a smoother on the coarsest level we use a direct solve there)
1080  Pre_smoothers_storage_pt.resize(Nlevel - 1, 0);
1081 
1082  // Allocate space for the post-smoother storage vector (remember, we do
1083  // not need a smoother on the coarsest level we use a direct solve there)
1084  Post_smoothers_storage_pt.resize(Nlevel - 1, 0);
1085 
1086  // Resize the vector storing all of the interpolation matrices
1088 
1089  // Resize the vector storing all of the restriction matrices
1090  Restriction_matrices_storage_pt.resize(Nlevel - 1, 0);
1091 
1092  if (!Suppress_all_output)
1093  {
1094  // Stop clock
1095  double t_m_end = TimingHelpers::timer();
1096  double total_setup_time = double(t_m_end - t_m_start);
1097  oomph_info
1098  << "\nCPU time for creation of hierarchy of MG problems [sec]: "
1099  << total_setup_time << std::endl;
1100 
1101  // Notify user that the hierarchy of levels is complete
1102  oomph_info
1103  << "\n===============Hierarchy Creation Complete================"
1104  << "\n"
1105  << std::endl;
1106  }
1107  } // End of setup_mg_hierarchy
virtual MGProblem * make_new_problem()=0
virtual void actions_before_adapt()
Definition: problem.h:1022

References oomph::Problem::actions_after_adapt(), oomph::Problem::actions_before_adapt(), oomph::Problem::assign_eqn_numbers(), oomph::MGProblem::make_new_problem(), oomph::MGProblem::mg_bulk_mesh_pt(), oomph::oomph_info, oomph::TreeBasedRefineableMeshBase::refine_base_mesh_as_in_reference_mesh_minus_one(), and oomph::TimingHelpers::timer().

◆ setup_mg_structures()

template<unsigned DIM>
void oomph::MGSolver< DIM >::setup_mg_structures
private

Set up the MG hierarchy structures.

Function to set up the hierachy of levels. Creates a vector of pointers to each MG level

1181  {
1182  // Initialise the timer start variable
1183  double t_m_start = 0.0;
1184 
1185  // Start the clock (if we're allowed to time things)
1186  if (!Suppress_all_output)
1187  {
1188  // Start the clock
1189  t_m_start = TimingHelpers::timer();
1190  }
1191 
1192  // Allocate space for the system matrix on each level
1193  for (unsigned i = 0; i < Nlevel; i++)
1194  {
1195  // Dynamically allocate a new CRDoubleMatrix
1196  Mg_matrices_storage_pt[i] = new CRDoubleMatrix;
1197  }
1198 
1199  // Loop over each level and extract the system matrix, solution vector
1200  // right-hand side vector and residual vector (to store the value of r=b-Ax)
1201  for (unsigned i = 0; i < Nlevel; i++)
1202  {
1203  // If we're allowed to output
1204  if (!Suppress_all_output)
1205  {
1206  // Output the level we're working on
1207  oomph_info << "Setting up MG structures on level: " << i << "\n"
1208  << std::endl;
1209  }
1210 
1211  // Resize the solution and RHS vector
1212  unsigned n_dof = Mg_hierarchy[i]->ndof();
1213  LinearAlgebraDistribution* dist_pt = new LinearAlgebraDistribution(
1214  Mg_hierarchy[i]->communicator_pt(), n_dof, false);
1215 
1216 #ifdef PARANOID
1217 #ifdef OOMPH_HAS_MPI
1218  // Set up the warning messages
1219  std::string warning_message = "Setup of distribution has not been ";
1220  warning_message += "tested with MPI.";
1221 
1222  // If we're not running the code in serial
1223  if (dist_pt->communicator_pt()->nproc() > 1)
1224  {
1225  // Throw a warning
1226  OomphLibWarning(
1228  }
1229 #endif
1230 #endif
1231 
1232  // Build the approximate solution
1233  X_mg_vectors_storage[i].clear();
1234  X_mg_vectors_storage[i].build(dist_pt);
1235 
1236  // Build the point source function
1237  Rhs_mg_vectors_storage[i].clear();
1238  Rhs_mg_vectors_storage[i].build(dist_pt);
1239 
1240  // Build the residual vector (r=b-Ax)
1241  Residual_mg_vectors_storage[i].clear();
1242  Residual_mg_vectors_storage[i].build(dist_pt);
1243 
1244  // Delete the distribution pointer
1245  delete dist_pt;
1246 
1247  // Make it a null pointer
1248  dist_pt = 0;
1249 
1250  // Build the matrix distribution
1251  Mg_matrices_storage_pt[i]->clear();
1252  Mg_matrices_storage_pt[i]->distribution_pt()->build(
1253  Mg_hierarchy[i]->communicator_pt(), n_dof, false);
1254 
1255  // Compute system matrix on the current level. On the finest level of the
1256  // hierarchy the system matrix and RHS vector is given by the Jacobian and
1257  // vector of residuals which define the original problem which the
1258  // Galerkin approximation to the system matrix is used on the subsequent
1259  // levels so that the correct contributions are taken from each dof on the
1260  // level above (that is to say, it should match the contribution taken
1261  // from the solution vector and RHS vector on the level above)
1262  if (i == 0)
1263  {
1264  // Initialise the timer start variable
1265  double t_jac_start = 0.0;
1266 
1267  // If we're allowed to output things
1268  if (!Suppress_all_output)
1269  {
1270  // Start timer for Jacobian setup
1271  t_jac_start = TimingHelpers::timer();
1272  }
1273 
1274  // The system matrix on the finest level is the Jacobian and the RHS
1275  // vector is given by the residual vector which accompanies the Jacobian
1276  Mg_hierarchy[0]->get_jacobian(Rhs_mg_vectors_storage[0],
1278 
1279  if (!Suppress_all_output)
1280  {
1281  // Document the time taken
1282  double t_jac_end = TimingHelpers::timer();
1283  double jacobian_setup_time = t_jac_end - t_jac_start;
1284  oomph_info << " - Time for setup of Jacobian [sec]: "
1285  << jacobian_setup_time << "\n"
1286  << std::endl;
1287  }
1288  }
1289  else
1290  {
1291  // Initialise the timer start variable
1292  double t_gal_start = 0.0;
1293 
1294  // If we're allowed
1295  if (!Suppress_all_output)
1296  {
1297  // Start timer for Galerkin matrix calculation
1298  t_gal_start = TimingHelpers::timer();
1299  }
1300 
1301  // The system matrix on the coarser levels must be formed using the
1302  // Galerkin approximation which we do by calculating the product
1303  // A^2h = I^2h_h * A^h * I^h_2h, i.e. the coarser version of the
1304  // finer grid system matrix is formed by multiplying by the (fine grid)
1305  // restriction matrix from the left and the (fine grid) interpolation
1306  // matrix from the left
1307 
1308  // First we need to calculate A^h * I^h_2h which we store as A^2h
1309  Mg_matrices_storage_pt[i - 1]->multiply(
1312 
1313  // Now calculate I^2h_h * (A^h * I^h_2h) where the quantity in brackets
1314  // was just calculated. This updates A^2h to give us the true
1315  // Galerkin approximation to the finer grid matrix
1316  Restriction_matrices_storage_pt[i - 1]->multiply(
1318 
1319  // If the user did not choose to suppress everything
1320  if (!Suppress_all_output)
1321  {
1322  // End timer for Galerkin matrix calculation
1323  double t_gal_end = TimingHelpers::timer();
1324 
1325  // Calculate setup time
1326  double galerkin_matrix_calculation_time = t_gal_end - t_gal_start;
1327 
1328  // Document the time taken
1329  oomph_info
1330  << " - Time for system matrix formation using the Galerkin "
1331  << "approximation [sec]: " << galerkin_matrix_calculation_time
1332  << "\n"
1333  << std::endl;
1334  }
1335  } // if (i==0) else
1336  } // for (unsigned i=0;i<Nlevel;i++)
1337 
1338  // If we're allowed to output
1339  if (!Suppress_all_output)
1340  {
1341  // Stop clock
1342  double t_m_end = TimingHelpers::timer();
1343  double total_setup_time = double(t_m_end - t_m_start);
1344  oomph_info << "Total CPU time for setup of MG structures [sec]: "
1345  << total_setup_time << std::endl;
1346 
1347  // Notify user that the hierarchy of levels is complete
1348  oomph_info << "\n============"
1349  << "Multigrid Structures Setup Complete"
1350  << "===========\n"
1351  << std::endl;
1352  }
1353  } // End of setup_mg_structures
double jacobian_setup_time() const
Definition: iterative_linear_solver.h:168

References oomph::LinearAlgebraDistribution::clear(), oomph::LinearAlgebraDistribution::communicator_pt(), i, oomph::OomphCommunicator::nproc(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::Global_string_for_annotation::string(), and oomph::TimingHelpers::timer().

◆ setup_smoothers()

template<unsigned DIM>
void oomph::MGSolver< DIM >::setup_smoothers
private

Set up the smoothers on all levels.

Function to set up all of the smoothers once the system matrices have been set up

1361  {
1362  // Initialise the timer start variable
1363  double t_m_start = 0.0;
1364 
1365  // Start the clock (if we're allowed to time things)
1366  if (!Suppress_all_output)
1367  {
1368  // Notify user
1369  oomph_info << "Starting the setup of all smoothers.\n" << std::endl;
1370 
1371  // Start the clock
1372  t_m_start = TimingHelpers::timer();
1373  }
1374 
1375  // Loop over the levels and assign the pre- and post-smoother points
1376  for (unsigned i = 0; i < Nlevel - 1; i++)
1377  {
1378  // If the pre-smoother factory function pointer hasn't been assigned
1379  // then we simply create a new instance of the DampedJacobi smoother
1380  // which is the default pre-smoother
1382  {
1383  Pre_smoothers_storage_pt[i] = new DampedJacobi<CRDoubleMatrix>;
1384  }
1385  // Otherwise we use the pre-smoother factory function pointer to
1386  // generate a new pre-smoother
1387  else
1388  {
1389  // Get a pointer to an object of the same type as the pre-smoother
1390  Pre_smoothers_storage_pt[i] = (*Pre_smoother_factory_function_pt)();
1391  }
1392 
1393  // If the post-smoother factory function pointer hasn't been assigned
1394  // then we simply create a new instance of the DampedJacobi smoother
1395  // which is the default post-smoother
1397  {
1398  Post_smoothers_storage_pt[i] = new DampedJacobi<CRDoubleMatrix>;
1399  }
1400  // Otherwise we use the post-smoother factory function pointer to
1401  // generate a new post-smoother
1402  else
1403  {
1404  // Get a pointer to an object of the same type as the post-smoother
1405  Post_smoothers_storage_pt[i] = (*Post_smoother_factory_function_pt)();
1406  }
1407  }
1408 
1409  // Set the tolerance for the pre- and post-smoothers. The norm of the
1410  // solution which is compared against the tolerance is calculated
1411  // differently to the multigrid solver. To ensure that the smoother
1412  // continues to solve for the prescribed number of iterations we
1413  // lower the tolerance
1414  for (unsigned i = 0; i < Nlevel - 1; i++)
1415  {
1416  // Set the tolerance of the i-th level pre-smoother
1417  Pre_smoothers_storage_pt[i]->tolerance() = 1.0e-16;
1418 
1419  // Set the tolerance of the i-th level post-smoother
1420  Post_smoothers_storage_pt[i]->tolerance() = 1.0e-16;
1421  }
1422 
1423  // Set the number of pre- and post-smoothing iterations in each
1424  // pre- and post-smoother
1425  for (unsigned i = 0; i < Nlevel - 1; i++)
1426  {
1427  // Set the number of pre-smoothing iterations as the value of Npre_smooth
1428  Pre_smoothers_storage_pt[i]->max_iter() = Npre_smooth;
1429 
1430  // Set the number of pre-smoothing iterations as the value of Npost_smooth
1431  Post_smoothers_storage_pt[i]->max_iter() = Npost_smooth;
1432  }
1433 
1434  // Complete the setup of all of the smoothers
1435  for (unsigned i = 0; i < Nlevel - 1; i++)
1436  {
1437  // Pass a pointer to the system matrix on the i-th level to the i-th
1438  // level pre-smoother
1440 
1441  // Pass a pointer to the system matrix on the i-th level to the i-th
1442  // level post-smoother
1444  }
1445 
1446  // Set up the distributions of each smoother
1447  for (unsigned i = 0; i < Nlevel - 1; i++)
1448  {
1449  // Get the number of dofs on the i-th level of the hierarchy.
1450  // This will be the same as the size of the solution vector
1451  // associated with the i-th level
1452  unsigned n_dof = X_mg_vectors_storage[i].nrow();
1453 
1454  // Create a LinearAlgebraDistribution which will be passed to the
1455  // linear solver
1456  LinearAlgebraDistribution dist(
1457  Mg_hierarchy[i]->communicator_pt(), n_dof, false);
1458 
1459 #ifdef PARANOID
1460 #ifdef OOMPH_HAS_MPI
1461  // Set up the warning messages
1462  std::string warning_message =
1463  "Setup of pre- and post-smoother distribution ";
1464  warning_message += "has not been tested with MPI.";
1465 
1466  // If we're not running the code in serial
1467  if (dist.communicator_pt()->nproc() > 1)
1468  {
1469  // Throw a warning
1470  OomphLibWarning(
1472  }
1473 #endif
1474 #endif
1475 
1476  // Build the distribution of the pre-smoother
1477  Pre_smoothers_storage_pt[i]->build_distribution(dist);
1478 
1479  // Build the distribution of the post-smoother
1480  Post_smoothers_storage_pt[i]->build_distribution(dist);
1481  }
1482 
1483  // Disable the smoother output on this level
1484  if (!Doc_time)
1485  {
1487  }
1488 
1489  // If we're allowed to output
1490  if (!Suppress_all_output)
1491  {
1492  // Stop clock
1493  double t_m_end = TimingHelpers::timer();
1494  double total_setup_time = double(t_m_end - t_m_start);
1495  oomph_info << "CPU time for setup of smoothers on all levels [sec]: "
1496  << total_setup_time << std::endl;
1497 
1498  // Notify user that the extraction is complete
1499  oomph_info
1500  << "\n==================Smoother Setup Complete================="
1501  << std::endl;
1502  }
1503  } // End of setup_smoothers
void disable_smoother_and_superlu_doc_time()
Suppress the output of both smoothers and SuperLU.
Definition: geometric_multigrid.h:308

References oomph::LinearAlgebraDistribution::communicator_pt(), i, oomph::OomphCommunicator::nproc(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::Global_string_for_annotation::string(), oomph::TimingHelpers::timer(), and oomph::IterativeLinearSolver::tolerance().

◆ setup_transfer_matrices()

template<unsigned DIM>
void oomph::MGSolver< DIM >::setup_transfer_matrices

Setup the transfer matrices on each level.

Set up the transfer matrices. Both the pure injection and full weighting method have been implemented here but it is highly recommended that full weighting is used in general. In both methods the transpose of the transfer matrix is used to transfer a vector back

1118  {
1119  // Initialise the timer start variable
1120  double t_r_start = 0.0;
1121 
1122  // Notify the user (if we're allowed)
1123  if (!Suppress_all_output)
1124  {
1125  // Notify user of progress
1126  oomph_info << "Creating the transfer matrices ";
1127 
1128  // Start the clock!
1129  t_r_start = TimingHelpers::timer();
1130  }
1131 
1132  // If we're allowed to output information
1133  if (!Suppress_all_output)
1134  {
1135  // Say what method we're using
1136  oomph_info << "using full weighting (recommended).\n" << std::endl;
1137  }
1138 
1139  // Using full weighting so use setup_interpolation_matrices.
1140  // Note: There are two methods to choose from here, the ideal choice is
1141  // setup_interpolation_matrices() but that requires a refineable mesh base
1142  if (dynamic_cast<TreeBasedRefineableMeshBase*>(
1144  {
1146  }
1147  // If the mesh is unstructured we have to use the locate_zeta function
1148  // to set up the interpolation matrices
1149  else
1150  {
1152  }
1153 
1154  // Loop over all levels that will be assigned a restriction matrix
1156 
1157  // If we're allowed
1158  if (!Suppress_all_output)
1159  {
1160  // Stop the clock
1161  double t_r_end = TimingHelpers::timer();
1162  double total_G_setup_time = double(t_r_end - t_r_start);
1163  oomph_info << "CPU time for transfer matrices setup [sec]: "
1164  << total_G_setup_time << std::endl;
1165 
1166  // Notify user that the hierarchy of levels is complete
1167  oomph_info
1168  << "\n============Transfer Matrices Setup Complete=============="
1169  << "\n"
1170  << std::endl;
1171  }
1172  } // End of setup_transfer_matrices function
void setup_interpolation_matrices()
Setup the interpolation matrix on each level.
Definition: geometric_multigrid.h:1510
void set_restriction_matrices_as_interpolation_transposes()
Definition: geometric_multigrid.h:465
void setup_interpolation_matrices_unstructured()
Setup the interpolation matrices.
Definition: geometric_multigrid.h:1832

References oomph::oomph_info, and oomph::TimingHelpers::timer().

◆ solve()

template<unsigned DIM>
void oomph::MGSolver< DIM >::solve ( Problem *const &  problem_pt,
DoubleVector result 
)
inlinevirtual

Virtual function in the base class that needs to be implemented later but for now just leave it empty

Implements oomph::LinearSolver.

510  {
511  // Dynamically cast problem_pt of type Problem to a MGProblem pointer
512  MGProblem* mg_problem_pt = dynamic_cast<MGProblem*>(problem_pt);
513 
514 #ifdef PARANOID
515  // PARANOID check - If the dynamic_cast produces a null pointer the
516  // input was not a MGProblem
517  if (0 == mg_problem_pt)
518  {
519  throw OomphLibError("Input problem must be of type MGProblem.",
522  }
523  // PARANOID check - If a node in the input problem has more than
524  // one value we cannot deal with it so arbitarily check the first one
525  if (problem_pt->mesh_pt()->node_pt(0)->nvalue() != 1)
526  {
527  // How many dofs are there in the first node
528  unsigned n_value = problem_pt->mesh_pt()->node_pt(0)->nvalue();
529 
530  // Make the error message
531  std::ostringstream error_message_stream;
532  error_message_stream << "Cannot currently deal with more than 1 dof"
533  << " per node. This problem has " << n_value
534  << " dofs per node." << std::endl;
535 
536  // Throw the error message
537  throw OomphLibError(error_message_stream.str(),
540  }
541 #endif
542 
543  // Assign the new MGProblem pointer to Mg_problem_pt
544  Mg_problem_pt = mg_problem_pt;
545 
546  // Set up all of the required MG structures
547  full_setup();
548 
549  // Run the MG method and assign the solution to result
550  mg_solve(result);
551 
552  // Only output if the V-cycle output isn't suppressed
554  {
555  // Notify user that the hierarchy of levels is complete
556  oomph_info << "\n================="
557  << "Multigrid Solve Complete"
558  << "=================\n"
559  << std::endl;
560  }
561 
562  // If the user did not request all output be suppressed
563  if (!Suppress_all_output)
564  {
565  // If the user requested all V-cycle output be suppressed
567  {
568  // Create an extra line spacing
569  oomph_info << std::endl;
570  }
571 
572  // Output number of V-cycles taken to solve
573  if (Has_been_solved)
574  {
575  oomph_info << "Total number of V-cycles required for solve: "
576  << V_cycle_counter << std::endl;
577  }
578  else
579  {
580  oomph_info << "Total number of V-cycles used: " << V_cycle_counter
581  << std::endl;
582  }
583  } // if (!Suppress_all_output)
584 
585  // Only enable and assign the stream pointer again if we originally
586  // suppressed everything otherwise it won't be set yet
588  {
589  // Now enable the stream pointer again
591  }
592  } // End of solve
void full_setup()
Runs a full setup of the MG solver.
Definition: geometric_multigrid.h:826
void mg_solve(DoubleVector &result)
Linear solver.
Definition: geometric_multigrid.h:2525

References oomph::MGSolver< DIM >::full_setup(), oomph::MGSolver< DIM >::Has_been_solved, oomph::Problem::mesh_pt(), oomph::MGSolver< DIM >::Mg_problem_pt, oomph::MGSolver< DIM >::mg_solve(), oomph::Mesh::node_pt(), oomph::Data::nvalue(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::MGSolver< DIM >::Stream_pt, oomph::OomphInfo::stream_pt(), oomph::MGSolver< DIM >::Suppress_all_output, oomph::MGSolver< DIM >::Suppress_v_cycle_output, and oomph::MGSolver< DIM >::V_cycle_counter.

Member Data Documentation

◆ Doc_everything

template<unsigned DIM>
bool oomph::MGSolver< DIM >::Doc_everything
private

If this is set to true we document everything. In addition to outputting the information of the setup timings and V-cycle data we document the refinement and unrefinement patterns given by the transfer operators which is done by keeping the coarser MG problem pointers alive

Referenced by oomph::MGSolver< DIM >::clean_up_memory(), and oomph::MGSolver< DIM >::enable_doc_everything().

◆ Has_been_setup

template<unsigned DIM>
bool oomph::MGSolver< DIM >::Has_been_setup
private

Boolean variable to indicate whether or not the solver has been setup.

Referenced by oomph::MGSolver< DIM >::clean_up_memory().

◆ Has_been_solved

template<unsigned DIM>
bool oomph::MGSolver< DIM >::Has_been_solved
private

Boolean variable to indicate whether or not the problem was successfully solved

Referenced by oomph::MGSolver< DIM >::solve().

◆ Interpolation_matrices_storage_pt

template<unsigned DIM>
Vector<CRDoubleMatrix*> oomph::MGSolver< DIM >::Interpolation_matrices_storage_pt
private

◆ Interpolation_self_test_vectors_storage

template<unsigned DIM>
Vector<DoubleVector> oomph::MGSolver< DIM >::Interpolation_self_test_vectors_storage
private

Vector to store the result of interpolation on each level (only required if the user wishes to document the output of interpolation and restriction on each level)

◆ Mg_hierarchy

template<unsigned DIM>
Vector<MGProblem*> oomph::MGSolver< DIM >::Mg_hierarchy
private

◆ Mg_matrices_storage_pt

◆ Mg_problem_pt

template<unsigned DIM>
MGProblem* oomph::MGSolver< DIM >::Mg_problem_pt
protected

Pointer to the MG problem (deep copy). This is protected to provide access to the MG preconditioner

Referenced by oomph::MGSolver< DIM >::MGSolver(), oomph::MGPreconditioner< DIM >::preconditioner_solve(), and oomph::MGSolver< DIM >::solve().

◆ Nlevel

◆ Npost_smooth

template<unsigned DIM>
unsigned oomph::MGSolver< DIM >::Npost_smooth
private

Number of post-smoothing steps.

Referenced by oomph::MGSolver< DIM >::npost_smooth().

◆ Npre_smooth

template<unsigned DIM>
unsigned oomph::MGSolver< DIM >::Npre_smooth
private

Number of pre-smoothing steps.

Referenced by oomph::MGSolver< DIM >::npre_smooth().

◆ Nvcycle

template<unsigned DIM>
unsigned oomph::MGSolver< DIM >::Nvcycle
protected

Maximum number of V-cycles (this is set as a protected variable so

Referenced by oomph::MGSolver< DIM >::max_iter(), and oomph::MGPreconditioner< DIM >::MGPreconditioner().

◆ Post_smoother_factory_function_pt

template<unsigned DIM>
PostSmootherFactoryFctPt oomph::MGSolver< DIM >::Post_smoother_factory_function_pt
private

Function to create post-smoothers.

Referenced by oomph::MGSolver< DIM >::set_post_smoother_factory_function().

◆ Post_smoothers_storage_pt

template<unsigned DIM>
Vector<Smoother*> oomph::MGSolver< DIM >::Post_smoothers_storage_pt
private

◆ Pre_smoother_factory_function_pt

template<unsigned DIM>
PreSmootherFactoryFctPt oomph::MGSolver< DIM >::Pre_smoother_factory_function_pt
private

Function to create pre-smoothers.

Referenced by oomph::MGSolver< DIM >::set_pre_smoother_factory_function().

◆ Pre_smoothers_storage_pt

template<unsigned DIM>
Vector<Smoother*> oomph::MGSolver< DIM >::Pre_smoothers_storage_pt
private

◆ Residual_mg_vectors_storage

template<unsigned DIM>
Vector<DoubleVector> oomph::MGSolver< DIM >::Residual_mg_vectors_storage
private

Vector to store the residual vectors.

Referenced by oomph::MGSolver< DIM >::pre_smooth(), and oomph::MGSolver< DIM >::residual_norm().

◆ Restriction_matrices_storage_pt

template<unsigned DIM>
Vector<CRDoubleMatrix*> oomph::MGSolver< DIM >::Restriction_matrices_storage_pt
private

◆ Restriction_self_test_vectors_storage

template<unsigned DIM>
Vector<DoubleVector> oomph::MGSolver< DIM >::Restriction_self_test_vectors_storage
private

Vector to store the result of restriction on each level (only required if the user wishes to document the output of interpolation and restriction on each level)

◆ Rhs_mg_vectors_storage

template<unsigned DIM>
Vector<DoubleVector> oomph::MGSolver< DIM >::Rhs_mg_vectors_storage
protected

Vector to store the RHS vectors (Rhs_mg). This is protected to allow the multigrid preconditioner to assign the RHS vector during preconditioner_solve()

Referenced by oomph::MGSolver< DIM >::direct_solve(), oomph::MGSolver< DIM >::post_smooth(), oomph::MGSolver< DIM >::pre_smooth(), oomph::MGPreconditioner< DIM >::preconditioner_solve(), and oomph::MGSolver< DIM >::residual_norm().

◆ Stream_pt

template<unsigned DIM>
std::ostream* oomph::MGSolver< DIM >::Stream_pt
protected

Pointer to the output stream – defaults to std::cout. This is protected member data to allow the preconditioner to restore normal output if everything was chosen to be suppressed by the user

Referenced by oomph::MGSolver< DIM >::disable_output(), oomph::MGPreconditioner< DIM >::preconditioner_solve(), oomph::MGPreconditioner< DIM >::setup(), and oomph::MGSolver< DIM >::solve().

◆ Suppress_all_output

template<unsigned DIM>
bool oomph::MGSolver< DIM >::Suppress_all_output
protected

If this is set to true then all output from the solver is suppressed. This is protected member data so that the multigrid preconditioner knows whether or not to restore the stream pointer

Referenced by oomph::MGSolver< DIM >::disable_output(), oomph::MGSolver< DIM >::enable_output(), oomph::MGPreconditioner< DIM >::preconditioner_solve(), oomph::MGPreconditioner< DIM >::setup(), and oomph::MGSolver< DIM >::solve().

◆ Suppress_v_cycle_output

template<unsigned DIM>
bool oomph::MGSolver< DIM >::Suppress_v_cycle_output
protected

Indicates whether or not the V-cycle output should be suppressed. Needs to be protected member data for the multigrid preconditioner to know whether or not to output information with each preconditioning step

Referenced by oomph::MGSolver< DIM >::disable_output(), oomph::MGSolver< DIM >::disable_v_cycle_output(), oomph::MGSolver< DIM >::enable_output(), oomph::MGSolver< DIM >::enable_v_cycle_output(), oomph::MGPreconditioner< DIM >::preconditioner_solve(), and oomph::MGSolver< DIM >::solve().

◆ V_cycle_counter

template<unsigned DIM>
unsigned oomph::MGSolver< DIM >::V_cycle_counter
private

Pointer to counter for V-cycles.

Referenced by oomph::MGSolver< DIM >::iterations(), and oomph::MGSolver< DIM >::solve().

◆ X_mg_vectors_storage

template<unsigned DIM>
Vector<DoubleVector> oomph::MGSolver< DIM >::X_mg_vectors_storage
private

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