Loading...
Searching...
No Matches
multigrid.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "solver.hpp"
4#include "util/table.hpp"
5
7
8/// @brief Multigrid solver for linear systems.
9///
10/// Satisfies the SolverLike concept (see solver.hpp).
11/// Supports arbitrary operators, prolongation/restriction, smoothers, and coarse grid solvers.
12/// Implements recursive V-cycle multigrid.
13/// @tparam OperatorT Operator type (must satisfy OperatorLike).
14/// @tparam ProlongationT Prolongation operator type (must satisfy OperatorLike).
15/// @tparam RestrictionT Restriction operator type (must satisfy OperatorLike).
16/// @tparam SmootherT Smoother type (must satisfy SolverLike).
17/// @tparam CoarseGridSolverT Coarse grid solver type (must satisfy SolverLike).
18template <
19 OperatorLike OperatorT,
20 OperatorLike ProlongationT,
21 OperatorLike RestrictionT,
22 SolverLike SmootherT,
23 SolverLike CoarseGridSolverT >
25{
26 public:
27 /// @brief Operator type to be solved.
28 using OperatorType = OperatorT;
29 /// @brief Prolongation operator type.
30 using ProlongationType = ProlongationT;
31 /// @brief Restriction operator type.
32 using RestrictionType = RestrictionT;
33 /// @brief Smoother type.
34 using SmootherType = SmootherT;
35 /// @brief Coarse grid solver type.
36 using CoarseGridSolverType = CoarseGridSolverT;
37
38 /// @brief Solution vector type.
40 /// @brief Right-hand side vector type.
42
43 /// @brief Scalar type for computations.
44 using ScalarType = SolutionVectorType::ScalarType;
45
46 private:
47 std::vector< ProlongationType > P_additive_; ///< Prolongation operators for each level.
48 std::vector< RestrictionType > R_; ///< Restriction operators for each level.
49 std::vector< OperatorT > A_c_; ///< Coarse grid operators for each level.
50 std::vector< SolutionVectorType > tmp_r_; ///< Temporary residual vectors for each level.
51 std::vector< SolutionVectorType > tmp_e_; ///< Temporary error vectors for each level.
52 std::vector< SolutionVectorType > tmp_; ///< Temporary workspace vectors for each level.
53 std::vector< SmootherType > smoothers_pre_; ///< Pre-smoothers for each level.
54 std::vector< SmootherType > smoothers_post_; ///< Post-smoothers for each level.
55 CoarseGridSolverType coarse_grid_solver_; ///< Coarse grid solver.
56
57 int num_cycles_; ///< Number of multigrid cycles to perform.
58 ScalarType relative_residual_threshold_; ///< Relative residual threshold for stopping.
59
60 std::shared_ptr< util::Table > statistics_; ///< Statistics table.
61 std::string tag_ = "multigrid"; ///< Tag for statistics output.
62
63 public:
64 /// @brief Construct a multigrid solver.
65 ///
66 /// Vector ordering of arguments always goes from the coarsest level (index 0) to the finest.
67 ///
68 /// @param P_additive Prolongation operators for each coarse level.
69 /// Size must match the number of levels - 1.
70 /// Must be additive prolongation operators, i.e., @code apply( P, x, y ) @endcode computes \f$ y = y + P x \f$.
71 /// @param R Restriction operators for each coarse level.
72 /// @param A_c Coarse grid operators for each coarse level.
73 /// @param tmp_r Temporary residual vectors for each coarse level.
74 /// @param tmp_e Temporary error vectors for each coarse level.
75 /// @param tmp Temporary workspace vectors for each level (including the finest level).
76 /// @param smoothers_pre Pre-smoothers for each level (including the finest level).
77 /// @param smoothers_post Post-smoothers for each level (including the finest level).
78 /// @param coarse_grid_solver Coarse grid solver.
79 /// @param num_cycles Number of multigrid cycles to perform.
80 /// @param relative_residual_threshold Relative residual threshold for stopping.
82 const std::vector< ProlongationType >& P_additive,
83 const std::vector< RestrictionType >& R,
84 const std::vector< OperatorT >& A_c,
85 const std::vector< SolutionVectorType >& tmp_r,
86 const std::vector< SolutionVectorType >& tmp_e,
87 const std::vector< SolutionVectorType >& tmp,
88 const std::vector< SmootherType >& smoothers_pre,
89 const std::vector< SmootherType >& smoothers_post,
90 const CoarseGridSolverType& coarse_grid_solver,
91 int num_cycles,
92 ScalarType relative_residual_threshold )
93 : P_additive_( P_additive )
94 , R_( R )
95 , A_c_( A_c )
96 , tmp_r_( tmp_r )
97 , tmp_e_( tmp_e )
98 , tmp_( tmp )
99 , smoothers_pre_( smoothers_pre )
100 , smoothers_post_( smoothers_post )
101 , coarse_grid_solver_( coarse_grid_solver )
102 , num_cycles_( num_cycles )
103 , relative_residual_threshold_( relative_residual_threshold )
104 {}
105
106 /// @brief Set a tag string for statistics output.
107 /// @param tag Tag string.
108 void set_tag( const std::string& tag ) { tag_ = tag; }
109
110 /// @brief Collect statistics in a shared table.
111 /// @param statistics Shared pointer to statistics table.
112 void collect_statistics( const std::shared_ptr< util::Table >& statistics ) { statistics_ = statistics; }
113
114 /// @brief Solve the linear system using multigrid cycles.
115 /// Calls the recursive V-cycle and updates statistics.
116 /// @param A Operator (matrix).
117 /// @param x Solution vector (output).
118 /// @param b Right-hand side vector (input).
120 {
121 if ( P_additive_.size() != A_c_.size() || R_.size() != A_c_.size() || tmp_r_.size() != A_c_.size() ||
122 tmp_e_.size() != A_c_.size() || tmp_.size() != A_c_.size() + 1 )
123 {
124 throw std::runtime_error(
125 "Multigrid: P_additive, R, A_c, tmp_e, and tmp_r must be available for all coarse levels. tmp "
126 "requires the finest grid allocated, too." );
127 }
128
129 const int max_level = P_additive_.size();
130
131 ScalarType initial_residual = 0.0;
132
133 if ( statistics_ )
134 {
135 apply( A, x, tmp_[max_level] );
136 lincomb( tmp_[max_level], { 1.0, -1.0 }, { b, tmp_[max_level] } );
137 initial_residual = norm_2( tmp_[max_level] );
138
139 statistics_->add_row(
140 { { "tag", tag_ },
141 { "cycle", 0 },
142 { "relative_residual", 1.0 },
143 { "absolute_residual", initial_residual },
144 { "residual_convergence_rate", 1.0 } } );
145 }
146
147 ScalarType previous_absolut_residual = initial_residual;
148
149 for ( int cycle = 1; cycle <= num_cycles_; ++cycle )
150 {
151 solve_recursive( A, x, b, max_level );
152
153 if ( statistics_ )
154 {
155 apply( A, x, tmp_[max_level] );
156 lincomb( tmp_[max_level], { 1.0, -1.0 }, { b, tmp_[max_level] } );
157 const auto absolute_residual = norm_2( tmp_[max_level] );
158
159 const auto relative_residual = absolute_residual / initial_residual;
160
161 statistics_->add_row(
162 { { "tag", tag_ },
163 { "cycle", cycle },
164 { "relative_residual", relative_residual },
165 { "absolute_residual", absolute_residual },
166 { "residual_convergence_rate", absolute_residual / previous_absolut_residual } } );
167
168 if ( relative_residual <= relative_residual_threshold_ )
169 {
170 return;
171 }
172
173 previous_absolut_residual = absolute_residual;
174 }
175 }
176 }
177
178 private:
179 /// @brief Recursive V-cycle multigrid solver.
180 /// @param A Operator (matrix) at current level.
181 /// @param x Solution vector (output) at current level.
182 /// @param b Right-hand side vector (input) at current level.
183 /// @param level Current multigrid level.
184 void solve_recursive( OperatorType& A, SolutionVectorType& x, const RHSVectorType& b, int level )
185 {
186 if ( level == 0 )
187 {
188 solve( coarse_grid_solver_, A, tmp_e_[0], tmp_r_[0] );
189 return;
190 }
191
192 // relax on Ax = b
193 solve( smoothers_pre_[level], A, x, b );
194
195 // compute the residual r = b - Ax
196 apply( A, x, tmp_[level] );
197 lincomb( tmp_[level], { 1.0, -1.0 }, { b, tmp_[level] } );
198
199 // restrict the residual r_c = R r_f
200 apply( R_[level - 1], tmp_[level], tmp_r_[level - 1] );
201
202 // solve (recursively) A_c e_c = r_c
203 assign( tmp_e_[level - 1], 0.0 );
204 solve_recursive( A_c_[level - 1], tmp_e_[level - 1], tmp_r_[level - 1], level - 1 );
205
206 // apply the coarse grid correction x = x + P e_c
207 apply( P_additive_[level - 1], tmp_e_[level - 1], x );
208
209 // relax on A x = b
210 solve( smoothers_post_[level], A, x, b );
211 }
212};
213
214} // namespace terra::linalg::solvers
Multigrid solver for linear systems.
Definition multigrid.hpp:25
SmootherT SmootherType
Smoother type.
Definition multigrid.hpp:34
void set_tag(const std::string &tag)
Set a tag string for statistics output.
Definition multigrid.hpp:108
ProlongationT ProlongationType
Prolongation operator type.
Definition multigrid.hpp:30
void collect_statistics(const std::shared_ptr< util::Table > &statistics)
Collect statistics in a shared table.
Definition multigrid.hpp:112
RestrictionT RestrictionType
Restriction operator type.
Definition multigrid.hpp:32
SrcOf< OperatorType > SolutionVectorType
Solution vector type.
Definition multigrid.hpp:39
OperatorT OperatorType
Operator type to be solved.
Definition multigrid.hpp:28
Multigrid(const std::vector< ProlongationType > &P_additive, const std::vector< RestrictionType > &R, const std::vector< OperatorT > &A_c, const std::vector< SolutionVectorType > &tmp_r, const std::vector< SolutionVectorType > &tmp_e, const std::vector< SolutionVectorType > &tmp, const std::vector< SmootherType > &smoothers_pre, const std::vector< SmootherType > &smoothers_post, const CoarseGridSolverType &coarse_grid_solver, int num_cycles, ScalarType relative_residual_threshold)
Construct a multigrid solver.
Definition multigrid.hpp:81
DstOf< OperatorType > RHSVectorType
Right-hand side vector type.
Definition multigrid.hpp:41
void solve_impl(OperatorType &A, SolutionVectorType &x, const RHSVectorType &b)
Solve the linear system using multigrid cycles. Calls the recursive V-cycle and updates statistics.
Definition multigrid.hpp:119
CoarseGridSolverT CoarseGridSolverType
Coarse grid solver type.
Definition multigrid.hpp:36
SolutionVectorType::ScalarType ScalarType
Scalar type for computations.
Definition multigrid.hpp:44
Definition block_preconditioner_2x2.hpp:7
void solve(Solver &solver, Operator &A, SolutionVector &x, const RHSVector &b)
Solve a linear system using the given solver and operator. Calls the solver's solve_impl method.
Definition solver.hpp:51
void lincomb(Vector &y, const std::vector< ScalarOf< Vector > > &c, const std::vector< Vector > &x, const ScalarOf< Vector > &c0)
Compute a linear combination of vectors. Implements: .
Definition vector.hpp:72
ScalarOf< Vector > norm_2(const Vector &y)
Compute the 2-norm (Euclidean norm) of a vector. Implements: .
Definition vector.hpp:166
Operator::SrcVectorType SrcOf
Alias for the source vector type of an operator.
Definition operator.hpp:145
void apply(LinearForm &L, typename LinearForm::DstVectorType &dst)
Apply a linear form and write to a destination vector.
Definition linear_form.hpp:37
Operator::DstVectorType DstOf
Alias for the destination vector type of an operator.
Definition operator.hpp:149
void assign(Vector &y, const ScalarOf< Vector > &c0)
Assign a scalar value to a vector. Implements: .
Definition vector.hpp:97