17 template <
typename V >
18 void apply(
const V&, V& )
const {}
19 template <
typename V >
47 SolverLike CoarseGridSolverT,
48 class RedistributeT = NoRedistribute >
72 std::vector< ProlongationType > P_additive_;
73 std::vector< RestrictionType > R_;
74 std::vector< OperatorT > A_c_;
75 std::vector< SolutionVectorType > tmp_r_;
76 std::vector< SolutionVectorType > tmp_e_;
77 std::vector< SolutionVectorType > tmp_;
78 std::vector< SmootherType > smoothers_pre_;
79 std::vector< SmootherType > smoothers_post_;
85 std::shared_ptr< util::Table > statistics_;
86 std::string tag_ =
"multigrid";
99 std::vector< RedistributeT > redistribute_down_;
100 std::vector< SolutionVectorType > tmp_r_fine_;
101 std::vector< SolutionVectorType > tmp_e_fine_;
122 const std::vector< ProlongationType >& P_additive,
123 const std::vector< RestrictionType >& R,
124 const std::vector< OperatorT >& A_c,
125 const std::vector< SolutionVectorType >& tmp_r,
126 const std::vector< SolutionVectorType >& tmp_e,
127 const std::vector< SolutionVectorType >& tmp,
128 const std::vector< SmootherType >& smoothers_pre,
129 const std::vector< SmootherType >& smoothers_post,
133 : P_additive_( P_additive )
139 , smoothers_pre_( smoothers_pre )
140 , smoothers_post_( smoothers_post )
141 , coarse_grid_solver_( coarse_grid_solver )
142 , num_cycles_( num_cycles )
143 , relative_residual_threshold_( relative_residual_threshold )
158 const std::vector< ProlongationType >& P_additive,
159 const std::vector< RestrictionType >& R,
160 const std::vector< OperatorT >& A_c,
161 const std::vector< SolutionVectorType >& tmp_r,
162 const std::vector< SolutionVectorType >& tmp_e,
163 const std::vector< SolutionVectorType >& tmp,
164 const std::vector< SmootherType >& smoothers_pre,
165 const std::vector< SmootherType >& smoothers_post,
169 std::vector< RedistributeT > redistribute_down,
170 std::vector< SolutionVectorType > tmp_r_fine,
171 std::vector< SolutionVectorType > tmp_e_fine )
172 : P_additive_( P_additive )
178 , smoothers_pre_( smoothers_pre )
179 , smoothers_post_( smoothers_post )
180 , coarse_grid_solver_( coarse_grid_solver )
181 , num_cycles_( num_cycles )
182 , relative_residual_threshold_( relative_residual_threshold )
183 , redistribute_down_( std::move( redistribute_down ) )
184 , tmp_r_fine_( std::move( tmp_r_fine ) )
185 , tmp_e_fine_( std::move( tmp_e_fine ) )
191 const bool all_empty = redistribute_down_.empty() && tmp_r_fine_.empty() && tmp_e_fine_.empty();
192 const bool all_sized = redistribute_down_.size() == A_c.size()
193 && tmp_r_fine_.size() == A_c.size()
194 && tmp_e_fine_.size() == A_c.size();
195 if ( !all_empty && !all_sized )
197 throw std::runtime_error(
198 "Multigrid (agglomerated): redistribute_down, tmp_r_fine, and tmp_e_fine must either all be empty "
199 "(agglomeration disabled) or each have one entry per coarse level." );
205 void set_tag(
const std::string& tag ) { tag_ = tag; }
209 void collect_statistics(
const std::shared_ptr< util::Table >& statistics ) { statistics_ = statistics; }
220 if ( P_additive_.size() != A_c_.size() || R_.size() != A_c_.size() || tmp_r_.size() != A_c_.size() ||
221 tmp_e_.size() != A_c_.size() || tmp_.size() != A_c_.size() + 1 )
223 throw std::runtime_error(
224 "Multigrid: P_additive, R, A_c, tmp_e, and tmp_r must be available for all coarse levels. tmp "
225 "requires the finest grid allocated, too." );
228 const int max_level = P_additive_.size();
235 apply( A, x, tmp_[max_level] );
236 lincomb( tmp_[max_level], { 1.0, -1.0 }, { b, tmp_[max_level] } );
237 initial_residual =
norm_2( tmp_[max_level] );
239 statistics_->add_row(
242 {
"relative_residual", 1.0 },
243 {
"absolute_residual", initial_residual },
244 {
"residual_convergence_rate", 1.0 } } );
247 ScalarType previous_absolut_residual = initial_residual;
249 for (
int cycle = 1; cycle <= num_cycles_; ++cycle )
253 solve_recursive( A, x, b, max_level );
259 apply( A, x, tmp_[max_level] );
260 lincomb( tmp_[max_level], { 1.0, -1.0 }, { b, tmp_[max_level] } );
261 const auto absolute_residual =
norm_2( tmp_[max_level] );
263 const auto relative_residual = absolute_residual / initial_residual;
265 statistics_->add_row(
268 {
"relative_residual", relative_residual },
269 {
"absolute_residual", absolute_residual },
270 {
"residual_convergence_rate", absolute_residual / previous_absolut_residual } } );
272 if ( relative_residual <= relative_residual_threshold_ )
277 previous_absolut_residual = absolute_residual;
293 solve( coarse_grid_solver_, A, tmp_e_[0], tmp_r_[0] );
297 const std::string level_suffix =
"_L" + std::to_string( level );
305 constexpr bool can_agglomerate = !std::is_same_v< RedistributeT, NoRedistribute >;
309 util::Timer t_sp(
"mg_smoother_pre" + level_suffix );
310 solve( smoothers_pre_[level], A, x, b );
313 bool active_at_coarse =
true;
315#ifdef TERRA_MG_AGGLOM_DEBUG
316 auto dbg = [&](
const char* phase ) {
317 int r; MPI_Comm_rank( MPI_COMM_WORLD, &r );
319 std::cout <<
"[MG_DBG] level=" << level <<
" phase=" << phase << std::endl << std::flush;
322 auto dbg = [](
const char* ) {};
325 if constexpr ( can_agglomerate )
331 if ( redistribute_down_.empty() )
335 util::Timer t_rr(
"mg_residual_and_restrict" + level_suffix );
336 apply( A, x, tmp_[level] );
337 lincomb( tmp_[level], { 1.0, -1.0 }, { b, tmp_[level] } );
338 apply( R_[level - 1], tmp_[level], tmp_r_[level - 1] );
341 assign( tmp_e_[level - 1], 0.0 );
342 solve_recursive( A_c_[level - 1], tmp_e_[level - 1], tmp_r_[level - 1], level - 1 );
345 util::Timer t_p(
"mg_prolongate_correct" + level_suffix );
346 apply( P_additive_[level - 1], tmp_e_[level - 1], x );
356 const bool identity_descent = redistribute_down_[level - 1].is_identity();
358 dbg(
"pre_smooth_done" );
360 util::Timer t_rr(
"mg_residual_and_restrict" + level_suffix );
361 apply( A, x, tmp_[level] );
362 dbg(
"residual_applied" );
363 lincomb( tmp_[level], { 1.0, -1.0 }, { b, tmp_[level] } );
364 apply( R_[level - 1],
366 identity_descent ? tmp_r_[level - 1] : tmp_r_fine_[level - 1] );
367 dbg(
"restriction_done" );
370 if ( !identity_descent )
372 util::Timer t_rd(
"mg_redistribute_down" + level_suffix );
373 redistribute_down_[level - 1].apply( tmp_r_fine_[level - 1].grid_data(),
374 tmp_r_[level - 1].grid_data() );
375 dbg(
"redistribute_down_done" );
377 active_at_coarse = ( tmp_r_[level - 1].comm() != MPI_COMM_NULL );
379 if ( active_at_coarse )
381 assign( tmp_e_[level - 1], 0.0 );
382 dbg(
"entering_coarse_recursion" );
383 solve_recursive( A_c_[level - 1], tmp_e_[level - 1], tmp_r_[level - 1], level - 1 );
384 dbg(
"returned_from_coarse" );
388 dbg(
"skipped_coarse_recursion" );
391 if ( !identity_descent )
393 util::Timer t_ru(
"mg_redistribute_up" + level_suffix );
394 redistribute_down_[level - 1].apply_transpose( tmp_e_[level - 1].grid_data(),
395 tmp_e_fine_[level - 1].grid_data() );
396 dbg(
"redistribute_up_done" );
400 util::Timer t_p(
"mg_prolongate_correct" + level_suffix );
401 apply( P_additive_[level - 1],
402 identity_descent ? tmp_e_[level - 1] : tmp_e_fine_[level - 1],
404 dbg(
"prolongation_done" );
412 util::Timer t_rr(
"mg_residual_and_restrict" + level_suffix );
413 apply( A, x, tmp_[level] );
414 lincomb( tmp_[level], { 1.0, -1.0 }, { b, tmp_[level] } );
415 apply( R_[level - 1], tmp_[level], tmp_r_[level - 1] );
418 assign( tmp_e_[level - 1], 0.0 );
419 solve_recursive( A_c_[level - 1], tmp_e_[level - 1], tmp_r_[level - 1], level - 1 );
422 util::Timer t_p(
"mg_prolongate_correct" + level_suffix );
423 apply( P_additive_[level - 1], tmp_e_[level - 1], x );
429 util::Timer t_sP(
"mg_smoother_post" + level_suffix );
430 solve( smoothers_post_[level], A, x, b );
Multigrid solver for linear systems.
Definition multigrid.hpp:50
CoarseGridSolverT CoarseGridSolverType
Coarse grid solver type.
Definition multigrid.hpp:61
OperatorT OperatorType
Operator type to be solved.
Definition multigrid.hpp:53
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:216
DstOf< OperatorType > RHSVectorType
Right-hand side vector type.
Definition multigrid.hpp:66
void set_tag(const std::string &tag)
Set a tag string for statistics output.
Definition multigrid.hpp:205
SrcOf< OperatorType > SolutionVectorType
Solution vector type.
Definition multigrid.hpp:64
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, std::vector< RedistributeT > redistribute_down, std::vector< SolutionVectorType > tmp_r_fine, std::vector< SolutionVectorType > tmp_e_fine)
Construct an agglomerated multigrid solver.
Definition multigrid.hpp:157
SmootherT SmootherType
Smoother type.
Definition multigrid.hpp:59
SolutionVectorType::ScalarType ScalarType
Scalar type for computations.
Definition multigrid.hpp:69
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:121
RestrictionT RestrictionType
Restriction operator type.
Definition multigrid.hpp:57
ProlongationT ProlongationType
Prolongation operator type.
Definition multigrid.hpp:55
void collect_statistics(const std::shared_ptr< util::Table > &statistics)
Collect statistics in a shared table.
Definition multigrid.hpp:209
Timer supporting RAII scope or manual stop.
Definition timer.hpp:342
Concept for types that behave like linear operators.
Definition operator.hpp:57
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
Placeholder redistribute type — methods never called when redistribute_down_ is empty....
Definition multigrid.hpp:16
void apply(const V &, V &) const
Definition multigrid.hpp:18
void apply_transpose(const V &, V &) const
Definition multigrid.hpp:20