ExaDG
Loading...
Searching...
No Matches
multigrid_algorithm.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2021 by the ExaDG authors
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * ______________________________________________________________________
20 */
21
22#ifndef INCLUDE_SOLVERS_AND_PRECONDITIONERS_MULTIGRID_PRECONDITIONER_H_
23#define INCLUDE_SOLVERS_AND_PRECONDITIONERS_MULTIGRID_PRECONDITIONER_H_
24
25// deal.II
26#include <deal.II/base/function_lib.h>
27#include <deal.II/base/timer.h>
28#include <deal.II/lac/la_parallel_vector.h>
29#include <deal.II/multigrid/mg_matrix.h>
30#include <deal.II/multigrid/mg_smoother.h>
31#include <deal.II/multigrid/mg_tools.h>
32#include <deal.II/multigrid/multigrid.h>
33
34// ExaDG
35#include <exadg/solvers_and_preconditioners/multigrid/transfer_base.h>
36#include <exadg/utilities/timer_tree.h>
37
38/*
39 * Activate timings if desired.
40 */
41#define ENABLE_TIMING false
42
43#ifndef ENABLE_TIMING
44# define ENABLE_TIMING false
45#endif
46
47namespace ExaDG
48{
49/*
50 * Re-implementation of multigrid preconditioner (V-cycle) in order to have more direct control over
51 * its individual components and avoid inner products and other expensive stuff.
52 */
53template<typename VectorType, typename MatrixType, typename SmootherType>
55{
56public:
57 MultigridAlgorithm(dealii::MGLevelObject<std::shared_ptr<MatrixType>> const & matrix,
59 MultigridTransferBase<VectorType> const & transfer,
60 dealii::MGLevelObject<std::shared_ptr<SmootherType>> const & smoother,
61 MPI_Comm const & comm,
62 unsigned int const n_cycles = 1)
63 : minlevel(matrix.min_level()),
64 maxlevel(matrix.max_level()),
65 defect(minlevel, maxlevel),
66 solution(minlevel, maxlevel),
67 t(minlevel, maxlevel),
68 matrix(&matrix, typeid(*this).name()),
69 coarse(&coarse, typeid(*this).name()),
70 transfer(transfer),
71 smoother(&smoother, typeid(*this).name()),
72 mpi_comm(comm),
73 n_cycles(n_cycles)
74 {
75 AssertThrow(n_cycles == 1, dealii::ExcNotImplemented());
76
77 for(unsigned int level = minlevel; level <= maxlevel; ++level)
78 {
79 matrix[level]->initialize_dof_vector(solution[level]);
80 defect[level] = solution[level];
81 t[level] = solution[level];
82 }
83
84 timer_tree = std::make_shared<TimerTree>();
85 }
86
87 template<class OtherVectorType>
88 void
89 vmult(OtherVectorType & dst, OtherVectorType const & src) const
90 {
91#if ENABLE_TIMING
92 dealii::Timer timer;
93#endif
94
95 for(unsigned int i = minlevel; i < maxlevel; i++)
96 {
97 defect[i] = 0.0;
98 }
99 defect[maxlevel].copy_locally_owned_data_from(src);
100
101 v_cycle(maxlevel, false);
102
103 dst.copy_locally_owned_data_from(solution[maxlevel]);
104
105#if ENABLE_TIMING
106 timer_tree->insert({"Multigrid"}, timer.wall_time());
107#endif
108 }
109
110 template<class OtherVectorType>
111 unsigned int
112 solve(OtherVectorType & dst, OtherVectorType const & src) const
113 {
114 defect[maxlevel].copy_locally_owned_data_from(src);
115
116 solution[maxlevel].copy_locally_owned_data_from(dst);
117
118 VectorType residual;
119 (*matrix)[maxlevel]->initialize_dof_vector(residual);
120
121 // calculate residual and check convergence
122 double const norm_r_0 = calculate_residual(residual);
123 double norm_r = norm_r_0;
124
125 int const max_iter = 1000;
126 double const abstol = 1.e-12;
127 double const reltol = 1.e-6;
128
129 int n_iter = 0;
130 bool converged = norm_r_0 < abstol;
131 while(not converged)
132 {
133 for(unsigned int i = minlevel; i < maxlevel; i++)
134 {
135 defect[i] = 0.0;
136 }
137
138 v_cycle(maxlevel, true);
139
140 // calculate residual and check convergence
141 norm_r = calculate_residual(residual);
142 std::cout << "Norm of residual = " << norm_r << std::endl;
143 converged = (norm_r < abstol or norm_r / norm_r_0 < reltol or n_iter >= max_iter);
144
145 ++n_iter;
146 }
147
148 dst.copy_locally_owned_data_from(solution[maxlevel]);
149
150 return n_iter;
151 }
152
153 template<class OtherVectorType>
154 double
155 calculate_residual(OtherVectorType & residual) const
156 {
157 (*matrix)[maxlevel]->vmult(residual, solution[maxlevel]);
158 residual.sadd(-1.0, 1.0, defect[maxlevel]);
159 return residual.l2_norm();
160 }
161
162 std::shared_ptr<TimerTree>
163 get_timings() const
164 {
165 return timer_tree;
166 }
167
168private:
172 void
173 v_cycle(unsigned int const level, bool const multigrid_is_a_solver) const
174 {
175#if ENABLE_TIMING
176 dealii::Timer timer;
177#endif
178
179 // call coarse grid solver
180 if(level == minlevel)
181 {
182#if ENABLE_TIMING
183 timer.restart();
184#endif
185
186 (*coarse)(level, solution[level], defect[level]);
187
188#if ENABLE_TIMING
189 timer_tree->insert({"Multigrid", "level " + std::to_string(level)}, timer.wall_time());
190#endif
191 }
192 else
193 {
194#if ENABLE_TIMING
195 timer.restart();
196#endif
197
198 // pre-smoothing
199 if(multigrid_is_a_solver)
200 {
201 // One has to take into account the initial guess of the solution when used as a solver
202 // and, therefore, call the function step().
203 (*smoother)[level]->step(solution[level], defect[level]);
204 }
205 else
206 {
207 // We can assume that solution[level] = 0 when used as a preconditioner
208 // and, therefore, call the function vmult(), which makes use of this assumption
209 // in order to apply optimizations (e.g., one does not need to evaluate the residual in
210 // the first iteration of the smoother).
211 (*smoother)[level]->vmult(solution[level], defect[level]);
212 }
213
214 // restriction
215 (*matrix)[level]->vmult_interface_down(t[level], solution[level]);
216 t[level].sadd(-1.0, 1.0, defect[level]);
217 transfer.restrict_and_add(level, defect[level - 1], t[level]);
218
219#if ENABLE_TIMING
220 timer_tree->insert({"Multigrid", "level " + std::to_string(level)}, timer.wall_time());
221#endif
222
223 // coarse grid correction
224 v_cycle(level - 1, false);
225
226#if ENABLE_TIMING
227 timer.restart();
228#endif
229
230 // prolongation
231 transfer.prolongate_and_add(level, solution[level], solution[level - 1]);
232
233 // post-smoothing
234 (*smoother)[level]->step(solution[level], defect[level]);
235
236#if ENABLE_TIMING
237 timer_tree->insert({"Multigrid", "level " + std::to_string(level)}, timer.wall_time());
238#endif
239 }
240 }
241
245 unsigned int minlevel;
246
250 unsigned int maxlevel;
251
256 mutable dealii::MGLevelObject<VectorType> defect;
257
261 mutable dealii::MGLevelObject<VectorType> solution;
262
266 mutable dealii::MGLevelObject<VectorType> t;
267
271 dealii::SmartPointer<dealii::MGLevelObject<std::shared_ptr<MatrixType>> const> matrix;
272
276 dealii::SmartPointer<dealii::MGCoarseGridBase<VectorType> const> coarse;
277
281 MultigridTransferBase<VectorType> const & transfer;
282
286 dealii::SmartPointer<dealii::MGLevelObject<std::shared_ptr<SmootherType>> const> smoother;
287
288 MPI_Comm const mpi_comm;
289
290 unsigned int const n_cycles;
291
292 std::shared_ptr<TimerTree> timer_tree;
293};
294
295} // namespace ExaDG
296
297#endif /* INCLUDE_SOLVERS_AND_PRECONDITIONERS_MULTIGRID_PRECONDITIONER_H_ */
Definition multigrid_algorithm.h:55
Definition transfer_base.h:29
Definition multigrid_preconditioner_base.h:55
Definition driver.cpp:33