ExaDG
Loading...
Searching...
No Matches
coarse_grid_solvers.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_MGCOARSEGRIDSOLVERS_H_
23#define INCLUDE_SOLVERS_AND_PRECONDITIONERS_MGCOARSEGRIDSOLVERS_H_
24
25// deal.II
26#include <deal.II/lac/la_parallel_vector.h>
27#include <deal.II/lac/solver_cg.h>
28#include <deal.II/lac/solver_control.h>
29#include <deal.II/lac/solver_gmres.h>
30#include <deal.II/multigrid/mg_base.h>
31#include <deal.II/numerics/vector_tools_mean_value.h>
32
33// ExaDG
34#include <exadg/solvers_and_preconditioners/multigrid/smoothers/chebyshev_smoother.h>
35#include <exadg/solvers_and_preconditioners/preconditioners/block_jacobi_preconditioner.h>
36#include <exadg/solvers_and_preconditioners/preconditioners/jacobi_preconditioner.h>
37#include <exadg/solvers_and_preconditioners/preconditioners/preconditioner_amg.h>
38#include <exadg/solvers_and_preconditioners/preconditioners/preconditioner_base.h>
39#include <exadg/solvers_and_preconditioners/solvers/iterative_solvers_dealii_wrapper.h>
40#include <exadg/solvers_and_preconditioners/solvers/solver_data.h>
41#include <exadg/solvers_and_preconditioners/utilities/linear_algebra_utilities.h>
42
43namespace ExaDG
44{
49template<typename Operator>
52 dealii::LinearAlgebra::distributed::Vector<typename Operator::value_type>>
53{
54public:
55 virtual ~CoarseGridSolverBase(){};
56
57 virtual void
58 update() = 0;
59};
60
61template<typename Operator>
62class MGCoarseKrylov : public CoarseGridSolverBase<Operator>
63{
64public:
65 typedef typename Operator::value_type Number;
66
67 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
68
70 {
75 : solver_type(MultigridCoarseGridSolver::CG),
76 solver_data(SolverData(1e4, 1.e-12, 1.e-3, 100)),
77 operator_is_singular(false),
78 preconditioner(MultigridCoarseGridPreconditioner::None),
79 amg_data(AMGData())
80 {
81 }
82
83 // Type of Krylov solver
84 MultigridCoarseGridSolver solver_type;
85
86 // Solver data
87 SolverData solver_data;
88
89 // in case of singular operators (with constant vectors forming the nullspace) the rhs vector
90 // has to be projected onto the space of vectors with zero mean prior to solving the coarse
91 // grid problem
92 bool operator_is_singular;
93
94 // Preconditioner
95 MultigridCoarseGridPreconditioner preconditioner;
96
97 // Configuration of AMG settings
98 AMGData amg_data;
99 };
100
101 MGCoarseKrylov(Operator const & pde_operator_in,
102 bool const initialize,
103 AdditionalData const & additional_data,
104 MPI_Comm const & comm)
105 : pde_operator(pde_operator_in), additional_data(additional_data), mpi_comm(comm)
106 {
107 if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::PointJacobi)
108 {
109 preconditioner = std::make_shared<JacobiPreconditioner<Operator>>(pde_operator, initialize);
110
111 std::shared_ptr<JacobiPreconditioner<Operator>> jacobi =
112 std::dynamic_pointer_cast<JacobiPreconditioner<Operator>>(preconditioner);
113 AssertDimension(jacobi->get_size_of_diagonal(), pde_operator.m());
114 }
115 else if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::BlockJacobi)
116 {
117 preconditioner =
118 std::make_shared<BlockJacobiPreconditioner<Operator>>(pde_operator, initialize);
119 }
120 else if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::AMG)
121 {
122 preconditioner =
123 std::make_shared<PreconditionerAMG<Operator, Number>>(pde_operator,
124 initialize,
125 additional_data.amg_data);
126 }
127 else
128 {
129 AssertThrow(
130 additional_data.preconditioner == MultigridCoarseGridPreconditioner::None or
131 additional_data.preconditioner == MultigridCoarseGridPreconditioner::PointJacobi or
132 additional_data.preconditioner == MultigridCoarseGridPreconditioner::BlockJacobi or
133 additional_data.preconditioner == MultigridCoarseGridPreconditioner::AMG,
134 dealii::ExcMessage("Specified preconditioner for PCG coarse grid solver not implemented."));
135 }
136 }
137
138 void
139 update() final
140 {
141 if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::None)
142 {
143 // do nothing
144 }
145 else if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::PointJacobi or
146 additional_data.preconditioner == MultigridCoarseGridPreconditioner::BlockJacobi or
147 additional_data.preconditioner == MultigridCoarseGridPreconditioner::AMG)
148 {
149 preconditioner->update();
150 }
151 else
152 {
153 AssertThrow(false, dealii::ExcMessage("Not implemented."));
154 }
155 }
156
157 void
158 operator()(unsigned int const, VectorType & dst, VectorType const & src) const final
159 {
160 VectorType r(src);
161 if(additional_data.operator_is_singular)
162 dealii::VectorTools::subtract_mean_value(r);
163
164 if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::AMG)
165 {
166 std::shared_ptr<PreconditionerAMG<Operator, Number>> preconditioner_amg =
167 std::dynamic_pointer_cast<PreconditionerAMG<Operator, Number>>(preconditioner);
168
169 AssertThrow(preconditioner_amg != nullptr,
170 dealii::ExcMessage("Constructed preconditioner is not of type "
171 "PreconditionerAMG<Operator, Number>."));
172
173 preconditioner_amg->apply_krylov_solver_with_amg_preconditioner(dst,
174 r,
175 additional_data.solver_type,
176 additional_data.solver_data);
177 }
178 else
179 {
180 std::shared_ptr<Krylov::SolverBase<VectorType>> solver;
181
182 if(additional_data.solver_type == MultigridCoarseGridSolver::CG)
183 {
184 Krylov::SolverDataCG solver_data;
185 solver_data.max_iter = additional_data.solver_data.max_iter;
186 solver_data.solver_tolerance_abs = additional_data.solver_data.abs_tol;
187 solver_data.solver_tolerance_rel = additional_data.solver_data.rel_tol;
188
189 if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::None)
190 {
191 solver_data.use_preconditioner = false;
192 }
193 else if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::PointJacobi or
194 additional_data.preconditioner == MultigridCoarseGridPreconditioner::BlockJacobi)
195 {
196 solver_data.use_preconditioner = true;
197 }
198 else
199 {
200 AssertThrow(false, dealii::ExcMessage("Not implemented."));
201 }
202
203 solver.reset(new Krylov::SolverCG<Operator, PreconditionerBase<Number>, VectorType>(
204 pde_operator, *preconditioner, solver_data));
205 }
206 else if(additional_data.solver_type == MultigridCoarseGridSolver::GMRES)
207 {
208 Krylov::SolverDataGMRES solver_data;
209
210 solver_data.max_iter = additional_data.solver_data.max_iter;
211 solver_data.solver_tolerance_abs = additional_data.solver_data.abs_tol;
212 solver_data.solver_tolerance_rel = additional_data.solver_data.rel_tol;
213 solver_data.max_n_tmp_vectors = additional_data.solver_data.max_krylov_size;
214
215 if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::None)
216 {
217 solver_data.use_preconditioner = false;
218 }
219 else if(additional_data.preconditioner == MultigridCoarseGridPreconditioner::PointJacobi or
220 additional_data.preconditioner == MultigridCoarseGridPreconditioner::BlockJacobi)
221 {
222 solver_data.use_preconditioner = true;
223 }
224 else
225 {
226 AssertThrow(false, dealii::ExcMessage("Not implemented."));
227 }
228
229 solver.reset(new Krylov::SolverGMRES<Operator, PreconditionerBase<Number>, VectorType>(
230 pde_operator, *preconditioner, solver_data, mpi_comm));
231 }
232 else
233 {
234 AssertThrow(false, dealii::ExcMessage("Not implemented."));
235 }
236
237 // Note that the preconditioner has already been updated
238 solver->solve(dst, r);
239 }
240 }
241
242private:
243 Operator const & pde_operator;
244
245 std::shared_ptr<PreconditionerBase<Number>> preconditioner;
246
247 AdditionalData additional_data;
248
249 MPI_Comm const mpi_comm;
250};
251
252
253template<typename Operator>
254class MGCoarseChebyshev : public CoarseGridSolverBase<Operator>
255{
256public:
257 typedef typename Operator::value_type MultigridNumber;
258
259 typedef dealii::LinearAlgebra::distributed::Vector<MultigridNumber> VectorType;
260
261 typedef dealii::PreconditionChebyshev<Operator, VectorType, dealii::DiagonalMatrix<VectorType>>
262 DealiiChebyshev;
263
264 MGCoarseChebyshev(Operator const & coarse_operator_in,
265 bool const initialize_preconditioner_in,
266 double const relative_tolerance_in,
267 MultigridCoarseGridPreconditioner const & preconditioner,
268 bool const operator_is_singular_in)
269 : coarse_operator(coarse_operator_in),
270 relative_tolerance(relative_tolerance_in),
271 operator_is_singular(operator_is_singular_in)
272 {
273 AssertThrow(preconditioner == MultigridCoarseGridPreconditioner::PointJacobi,
274 dealii::ExcMessage(
275 "Only PointJacobi preconditioner implemented for Chebyshev coarse-grid solver."));
276
277 if(initialize_preconditioner_in)
278 {
279 update();
280 }
281 }
282
283 void
284 update() final
285 {
286 // use Chebyshev smoother of high degree to solve the coarse grid problem approximately
287 typename DealiiChebyshev::AdditionalData dealii_additional_data;
288
289 std::shared_ptr<dealii::DiagonalMatrix<VectorType>> diagonal_matrix =
290 std::make_shared<dealii::DiagonalMatrix<VectorType>>();
291 VectorType & diagonal_vector = diagonal_matrix->get_vector();
292
293 coarse_operator.initialize_dof_vector(diagonal_vector);
294 coarse_operator.calculate_inverse_diagonal(diagonal_vector);
295
296 std::pair<double, double> eigenvalues =
297 compute_eigenvalues(coarse_operator, diagonal_vector, operator_is_singular);
298
299 double const factor = 1.1;
300
301 dealii_additional_data.preconditioner = diagonal_matrix;
302 dealii_additional_data.max_eigenvalue = factor * eigenvalues.second;
303 dealii_additional_data.smoothing_range = eigenvalues.second / eigenvalues.first * factor;
304
305 double sigma = (1. - std::sqrt(1. / dealii_additional_data.smoothing_range)) /
306 (1. + std::sqrt(1. / dealii_additional_data.smoothing_range));
307
308 // calculate/estimate the number of Chebyshev iterations needed to reach a specified relative
309 // solver tolerance
310 double const eps = relative_tolerance;
311
312 dealii_additional_data.degree = static_cast<unsigned int>(
313 std::log(1. / eps + std::sqrt(1. / eps / eps - 1.)) / std::log(1. / sigma));
314 dealii_additional_data.eig_cg_n_iterations = 0;
315
316 chebyshev_smoother = std::make_shared<DealiiChebyshev>();
317 chebyshev_smoother->initialize(coarse_operator, dealii_additional_data);
318 }
319
320 void
321 operator()(unsigned int const level, VectorType & dst, const VectorType & src) const final
322 {
323 AssertThrow(chebyshev_smoother.get() != 0,
324 dealii::ExcMessage("MGCoarseChebyshev: chebyshev_smoother is not initialized."));
325
326 AssertThrow(level == 0, dealii::ExcNotImplemented());
327
328 chebyshev_smoother->vmult(dst, src);
329 }
330
331private:
332 Operator const & coarse_operator;
333 double const relative_tolerance;
334 bool const operator_is_singular;
335
336 std::shared_ptr<DealiiChebyshev> chebyshev_smoother;
337};
338
343template<typename Operator>
344class MGCoarseAMG : public CoarseGridSolverBase<Operator>
345{
346private:
347 typedef typename Operator::value_type Number;
348
349 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
350
351public:
352 MGCoarseAMG(Operator const & op, bool const initialize, AMGData data = AMGData())
353 {
354 amg_preconditioner =
355 std::make_shared<PreconditionerAMG<Operator, Number>>(op, initialize, data);
356 }
357
358 void
359 update() final
360 {
361 amg_preconditioner->update();
362 }
363
364 void
365 operator()(unsigned int const /*level*/, VectorType & dst, VectorType const & src) const final
366 {
367 amg_preconditioner->vmult(dst, src);
368 }
369
370private:
371 std::shared_ptr<PreconditionerAMG<Operator, Number>> amg_preconditioner;
372};
373
374} // namespace ExaDG
375
376#endif /* INCLUDE_SOLVERS_AND_PRECONDITIONERS_MGCOARSEGRIDSOLVERS_H_ */
Definition coarse_grid_solvers.h:53
Definition coarse_grid_solvers.h:63
Definition multigrid_preconditioner_base.h:55
Definition driver.cpp:33
Definition multigrid_parameters.h:98
Definition coarse_grid_solvers.h:70
AdditionalData()
Definition coarse_grid_solvers.h:74
Definition solver_data.h:34