ExaDG
Loading...
Searching...
No Matches
iterative_solvers_dealii_wrapper.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_ITERATIVESOLVERS_H_
23#define INCLUDE_SOLVERS_AND_PRECONDITIONERS_ITERATIVESOLVERS_H_
24
25// deal.II
26#include <deal.II/base/timer.h>
27#include <deal.II/lac/precondition.h>
28#include <deal.II/lac/solver_cg.h>
29#include <deal.II/lac/solver_gmres.h>
30
31// ExaDG
32#include <exadg/utilities/timer_tree.h>
33
34namespace ExaDG
35{
36namespace Krylov
37{
38template<typename VectorType>
40{
41public:
42 SolverBase() : l2_0(1.0), l2_n(1.0), n(0), rho(0.0), n10(0)
43 {
44 timer_tree = std::make_shared<TimerTree>();
45 }
46
47 virtual unsigned int
48 solve(VectorType & dst, VectorType const & rhs) const = 0;
49
50 virtual ~SolverBase()
51 {
52 }
53
54 virtual void
55 update_preconditioner(bool const update_preconditioner) const = 0;
56
57 template<typename Control>
58 void
59 compute_performance_metrics(Control const & solver_control) const
60 {
61 // get some statistics related to convergence
62 this->l2_0 = solver_control.initial_value();
63 this->l2_n = solver_control.last_value();
64 this->n = solver_control.last_step();
65
66 // compute some derived performance metrics
67 if(n > 0)
68 {
69 this->rho = std::pow(l2_n / l2_0, 1.0 / n);
70 this->n10 = -10.0 * std::log(10.0) / std::log(rho);
71 }
72 }
73
74 virtual std::shared_ptr<TimerTree>
75 get_timings() const
76 {
77 return timer_tree;
78 }
79
80 // performance metrics
81 mutable double l2_0; // norm of initial residual
82 mutable double l2_n; // norm of final residual
83 mutable unsigned int n; // number of iterations
84 mutable double rho; // average convergence rate
85 mutable double n10; // number of iterations needed to reduce the residual by 1e10
86
87protected:
88 std::shared_ptr<TimerTree> timer_tree;
89};
90
92{
94 : max_iter(1e4),
95 solver_tolerance_abs(1.e-20),
96 solver_tolerance_rel(1.e-6),
97 use_preconditioner(false),
98 compute_performance_metrics(false)
99 {
100 }
101
102 unsigned int max_iter;
103 double solver_tolerance_abs;
104 double solver_tolerance_rel;
105 bool use_preconditioner;
106 bool compute_performance_metrics;
107};
108
109template<typename Operator, typename Preconditioner, typename VectorType>
110class SolverCG : public SolverBase<VectorType>
111{
112public:
113 SolverCG(Operator const & underlying_operator_in,
114 Preconditioner & preconditioner_in,
115 SolverDataCG const & solver_data_in)
116 : underlying_operator(underlying_operator_in),
117 preconditioner(preconditioner_in),
118 solver_data(solver_data_in)
119 {
120 }
121
122 void
123 update_preconditioner(bool const update_preconditioner) const override
124 {
125 if(solver_data.use_preconditioner)
126 {
127 if(preconditioner.needs_update() or update_preconditioner)
128 {
129 preconditioner.update();
130 }
131 }
132 }
133
134 unsigned int
135 solve(VectorType & dst, VectorType const & rhs) const override
136 {
137 dealii::Timer timer;
138
139 dealii::ReductionControl solver_control(solver_data.max_iter,
140 solver_data.solver_tolerance_abs,
141 solver_data.solver_tolerance_rel);
142
143 dealii::SolverCG<VectorType> solver(solver_control);
144
145 if(solver_data.use_preconditioner == false)
146 {
147 solver.solve(underlying_operator, dst, rhs, dealii::PreconditionIdentity());
148 }
149 else
150 {
151 solver.solve(underlying_operator, dst, rhs, preconditioner);
152 }
153
154 AssertThrow(std::isfinite(solver_control.last_value()),
155 dealii::ExcMessage("Last iteration step contained NaN or Inf values."));
156
157 if(solver_data.compute_performance_metrics)
158 this->compute_performance_metrics(solver_control);
159
160 this->timer_tree->insert({"SolverCG"}, timer.wall_time());
161
162 return solver_control.last_step();
163 }
164
165 std::shared_ptr<TimerTree>
166 get_timings() const override
167 {
168 if(solver_data.use_preconditioner)
169 {
170 this->timer_tree->insert({"SolverCG"}, preconditioner.get_timings());
171 }
172
173 return this->timer_tree;
174 }
175
176private:
177 Operator const & underlying_operator;
178 Preconditioner & preconditioner;
179 SolverDataCG const solver_data;
180};
181
182template<class Number>
183void
184output_eigenvalues(const std::vector<Number> & eigenvalues,
185 std::string const & text,
186 MPI_Comm const & mpi_comm)
187{
188 if(dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0)
189 {
190 std::cout << text << std::endl;
191 for(unsigned int j = 0; j < eigenvalues.size(); ++j)
192 {
193 std::cout << ' ' << eigenvalues.at(j) << std::endl;
194 }
195 std::cout << std::endl;
196 }
197}
198
200{
202 : max_iter(1e4),
203 solver_tolerance_abs(1.e-20),
204 solver_tolerance_rel(1.e-6),
205 use_preconditioner(false),
206 max_n_tmp_vectors(30),
207 compute_eigenvalues(false),
208 compute_performance_metrics(false)
209 {
210 }
211
212 unsigned int max_iter;
213 double solver_tolerance_abs;
214 double solver_tolerance_rel;
215 bool use_preconditioner;
216 unsigned int max_n_tmp_vectors;
217 bool compute_eigenvalues;
218 bool compute_performance_metrics;
219};
220
221template<typename Operator, typename Preconditioner, typename VectorType>
222class SolverGMRES : public SolverBase<VectorType>
223{
224public:
225 SolverGMRES(Operator const & underlying_operator_in,
226 Preconditioner & preconditioner_in,
227 SolverDataGMRES const & solver_data_in,
228 MPI_Comm const & mpi_comm_in)
229 : underlying_operator(underlying_operator_in),
230 preconditioner(preconditioner_in),
231 solver_data(solver_data_in),
232 mpi_comm(mpi_comm_in)
233 {
234 }
235
236 virtual ~SolverGMRES()
237 {
238 }
239
240 void
241 update_preconditioner(bool const update_preconditioner) const override
242 {
243 if(solver_data.use_preconditioner)
244 {
245 if(preconditioner.needs_update() or update_preconditioner)
246 {
247 preconditioner.update();
248 }
249 }
250 }
251
252 unsigned int
253 solve(VectorType & dst, VectorType const & rhs) const override
254 {
255 dealii::Timer timer;
256
257 dealii::ReductionControl solver_control(solver_data.max_iter,
258 solver_data.solver_tolerance_abs,
259 solver_data.solver_tolerance_rel);
260
261 typename dealii::SolverGMRES<VectorType>::AdditionalData additional_data;
262 additional_data.max_n_tmp_vectors = solver_data.max_n_tmp_vectors;
263 additional_data.right_preconditioning = true;
264 dealii::SolverGMRES<VectorType> solver(solver_control, additional_data);
265
266 if(solver_data.compute_eigenvalues == true)
267 {
268 solver.connect_eigenvalues_slot(std::bind(output_eigenvalues<std::complex<double>>,
269 std::placeholders::_1,
270 "Eigenvalues: ",
271 mpi_comm),
272 true);
273 }
274
275 if(solver_data.use_preconditioner == false)
276 {
277 solver.solve(underlying_operator, dst, rhs, dealii::PreconditionIdentity());
278 }
279 else
280 {
281 solver.solve(this->underlying_operator, dst, rhs, this->preconditioner);
282 }
283
284 AssertThrow(std::isfinite(solver_control.last_value()),
285 dealii::ExcMessage("Last iteration step contained NaN or Inf values."));
286
287 if(solver_data.compute_performance_metrics)
288 this->compute_performance_metrics(solver_control);
289
290 this->timer_tree->insert({"SolverGMRES"}, timer.wall_time());
291
292 return solver_control.last_step();
293 }
294
295 std::shared_ptr<TimerTree>
296 get_timings() const override
297 {
298 if(solver_data.use_preconditioner)
299 {
300 this->timer_tree->insert({"SolverGMRES"}, preconditioner.get_timings());
301 }
302
303 return this->timer_tree;
304 }
305
306private:
307 Operator const & underlying_operator;
308 Preconditioner & preconditioner;
309 SolverDataGMRES const solver_data;
310
311 MPI_Comm const mpi_comm;
312};
313
315{
317 : max_iter(1e4),
318 solver_tolerance_abs(1.e-20),
319 solver_tolerance_rel(1.e-6),
320 use_preconditioner(false),
321 max_n_tmp_vectors(30),
322 compute_performance_metrics(false)
323 {
324 }
325
326 unsigned int max_iter;
327 double solver_tolerance_abs;
328 double solver_tolerance_rel;
329 bool use_preconditioner;
330 unsigned int max_n_tmp_vectors;
331 bool compute_performance_metrics;
332};
333
334template<typename Operator, typename Preconditioner, typename VectorType>
335class SolverFGMRES : public SolverBase<VectorType>
336{
337public:
338 SolverFGMRES(Operator const & underlying_operator_in,
339 Preconditioner & preconditioner_in,
340 SolverDataFGMRES const & solver_data_in)
341 : underlying_operator(underlying_operator_in),
342 preconditioner(preconditioner_in),
343 solver_data(solver_data_in)
344 {
345 }
346
347 virtual ~SolverFGMRES()
348 {
349 }
350
351 void
352 update_preconditioner(bool const update_preconditioner) const override
353 {
354 if(solver_data.use_preconditioner)
355 {
356 if(preconditioner.needs_update() or update_preconditioner)
357 {
358 preconditioner.update();
359 }
360 }
361 }
362
363 unsigned int
364 solve(VectorType & dst, VectorType const & rhs) const override
365 {
366 dealii::Timer timer;
367
368 dealii::ReductionControl solver_control(solver_data.max_iter,
369 solver_data.solver_tolerance_abs,
370 solver_data.solver_tolerance_rel);
371
372 typename dealii::SolverFGMRES<VectorType>::AdditionalData additional_data;
373 additional_data.max_basis_size = solver_data.max_n_tmp_vectors;
374 // FGMRES always uses right preconditioning
375
376 dealii::SolverFGMRES<VectorType> solver(solver_control, additional_data);
377
378 if(solver_data.use_preconditioner == false)
379 {
380 solver.solve(underlying_operator, dst, rhs, dealii::PreconditionIdentity());
381 }
382 else
383 {
384 solver.solve(underlying_operator, dst, rhs, preconditioner);
385 }
386
387 AssertThrow(std::isfinite(solver_control.last_value()),
388 dealii::ExcMessage("Last iteration step contained NaN or Inf values."));
389
390 if(solver_data.compute_performance_metrics)
391 this->compute_performance_metrics(solver_control);
392
393 this->timer_tree->insert({"SolverFGMRES"}, timer.wall_time());
394
395 return solver_control.last_step();
396 }
397
398 std::shared_ptr<TimerTree>
399 get_timings() const override
400 {
401 if(solver_data.use_preconditioner)
402 {
403 this->timer_tree->insert({"SolverFGMRES"}, preconditioner.get_timings());
404 }
405
406 return this->timer_tree;
407 }
408
409private:
410 Operator const & underlying_operator;
411 Preconditioner & preconditioner;
412 SolverDataFGMRES const solver_data;
413};
414} // namespace Krylov
415
416} // namespace ExaDG
417
418#endif /* INCLUDE_SOLVERS_AND_PRECONDITIONERS_ITERATIVESOLVERS_H_ */
Definition iterative_solvers_dealii_wrapper.h:40
Definition iterative_solvers_dealii_wrapper.h:111
Definition iterative_solvers_dealii_wrapper.h:336
Definition iterative_solvers_dealii_wrapper.h:223
Definition driver.cpp:33
Definition iterative_solvers_dealii_wrapper.h:92
Definition iterative_solvers_dealii_wrapper.h:315
Definition iterative_solvers_dealii_wrapper.h:200