ExaDG
Loading...
Searching...
No Matches
compute_eigenvalues.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 EXADG_SOLVERS_AND_PRECONDITIONERS_UTILITIES_COMPUTE_EIGENVALUES_H_
23#define EXADG_SOLVERS_AND_PRECONDITIONERS_UTILITIES_COMPUTE_EIGENVALUES_H_
24
25// deal.II
26#include <deal.II/numerics/vector_tools_mean_value.h>
27
28// ExaDG
29#include <exadg/solvers_and_preconditioners/preconditioners/jacobi_preconditioner.h>
30#include <exadg/solvers_and_preconditioners/solvers/solver_data.h>
31
32namespace ExaDG
33{
34/*
35 * Utility function to estimate the Eigenvalues of `Operator` via a
36 * conjugate gradient solve preconditioned by the inverse diagonal.
37 */
38template<typename Operator, typename VectorType>
39std::pair<double, double>
40estimate_eigenvalues_cg(Operator const & underlying_operator,
41 VectorType const & inverse_diagonal,
42 bool const operator_is_singular,
43 unsigned int const eig_n_iter = 10000)
44{
45 VectorType solution, rhs;
46 solution.reinit(inverse_diagonal);
47 rhs.reinit(inverse_diagonal, true);
48 // seed `rand` in order to obtain reproducible results
49 srand(1);
50 for(unsigned int i = 0; i < rhs.locally_owned_size(); ++i)
51 rhs.local_element(i) = (double)rand() / RAND_MAX;
52 if(operator_is_singular)
53 dealii::VectorTools::subtract_mean_value(rhs);
54
55 dealii::SolverControl control(eig_n_iter, rhs.l2_norm() * 1e-5);
56 dealii::internal::EigenvalueTracker eigenvalue_tracker;
57
58 dealii::SolverCG<VectorType> solver(control);
59
60 solver.connect_eigenvalues_slot(std::bind(&dealii::internal::EigenvalueTracker::slot,
61 &eigenvalue_tracker,
62 std::placeholders::_1),
63 false /* every_iteration */);
64
65 JacobiPreconditioner<Operator> preconditioner(underlying_operator, true /* initialize */);
66
67 try
68 {
69 solver.solve(underlying_operator, solution, rhs, preconditioner);
70 }
71 catch(dealii::SolverControl::NoConvergence &)
72 {
73 // accept the current estimates despite non-convergence
74 }
75
76 std::pair<double, double> eigenvalues_min_max;
77 if(eigenvalue_tracker.values.empty())
78 {
79 eigenvalues_min_max.first = eigenvalues_min_max.second = 1.;
80 }
81 else
82 {
83 eigenvalues_min_max.first = eigenvalue_tracker.values.front();
84 eigenvalues_min_max.second = eigenvalue_tracker.values.back();
85 }
86
87 return eigenvalues_min_max;
88}
89
90// Struct to track complex eigenvalues similar to `dealii::internals::EigenValueTracker`.
92{
93public:
94 void
95 slot(std::vector<std::complex<double>> const & eigenvalues)
96 {
97 values = eigenvalues;
98 }
99
100 std::vector<std::complex<double>> values;
101};
102
103/*
104 * Utility function to estimate and print the Eigenvalues of `Operator` via a preconditioned GMRES
105 * solve. This function is used for debugging only and assumes a previous solve such that `solution`
106 * and `rhs` solve the system up to tolerance already.
107 */
108template<typename Operator, typename Preconditioner, typename VectorType>
109std::vector<std::complex<double>>
110estimate_eigenvalues_gmres(Operator const & underlying_operator,
111 Preconditioner const & preconditioner,
112 VectorType const & solution,
113 VectorType const & rhs,
114 SolverData const & solver_data,
115 bool const print)
116{
117 // initial guess
118 VectorType tmp(solution);
119
120 dealii::ReductionControl solver_control(solver_data.max_iter,
121 solver_data.abs_tol,
122 solver_data.rel_tol);
123
124 typename dealii::SolverGMRES<VectorType>::AdditionalData additional_data;
125 additional_data.max_n_tmp_vectors = solver_data.max_krylov_size;
126 additional_data.right_preconditioning = true;
127 dealii::SolverGMRES<VectorType> solver(solver_control, additional_data);
128
129 EigenvalueTracker eigenvalue_tracker;
130 solver.connect_eigenvalues_slot(std::bind(&EigenvalueTracker::slot,
131 &eigenvalue_tracker,
132 std::placeholders::_1),
133 true /* every_iteration */);
134
135 try
136 {
137 solver.solve(underlying_operator, tmp, rhs, preconditioner);
138 }
139 catch(dealii::SolverControl::NoConvergence &)
140 {
141 // accept the current estimates despite non-convergence
142 }
143
144 std::vector<std::complex<double>> const & eigenvalues = eigenvalue_tracker.values;
145
146 if(print)
147 {
148 MPI_Comm const & mpi_comm = solution.get_mpi_communicator();
149 if(dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0)
150 {
151 std::cout << "Approximate eigenvalues:\n";
152 for(unsigned int j = 0; j < eigenvalues.size(); ++j)
153 {
154 std::cout << ' ' << eigenvalues[j] << "\n";
155 }
156 std::cout << "\n";
157 }
158 }
159
160 return eigenvalues;
161}
162} // namespace ExaDG
163
164#endif /* EXADG_SOLVERS_AND_PRECONDITIONERS_UTILITIES_COMPUTE_EIGENVALUES_H_ */
Definition jacobi_preconditioner.h:35
Definition driver.cpp:33
Definition compute_eigenvalues.h:92
Definition solver_data.h:92