ExaDG
Loading...
Searching...
No Matches
inverse_mass_operator.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_OPERATORS_INVERSEMASSMATRIX_H_
23#define INCLUDE_OPERATORS_INVERSEMASSMATRIX_H_
24
25// deal.II
26#include <deal.II/lac/la_parallel_vector.h>
27#include <deal.II/matrix_free/operators.h>
28
29// ExaDG
30#include <exadg/matrix_free/integrators.h>
31#include <exadg/operators/inverse_mass_parameters.h>
32#include <exadg/operators/mass_operator.h>
33#include <exadg/solvers_and_preconditioners/preconditioners/block_jacobi_preconditioner.h>
34#include <exadg/solvers_and_preconditioners/preconditioners/jacobi_preconditioner.h>
35
36namespace ExaDG
37{
39{
40 InverseMassOperatorData() : dof_index(0), quad_index(0)
41 {
42 }
43
44 // Parameters referring to dealii::MatrixFree
45 unsigned int dof_index;
46 unsigned int quad_index;
47
48 InverseMassParameters parameters;
49};
50
51template<int dim, int n_components, typename Number>
53{
54private:
55 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
56
58
59 typedef CellIntegrator<dim, n_components, Number> Integrator;
60
61 // use a template parameter of -1 to select the precompiled version of this operator
62 typedef dealii::MatrixFreeOperators::CellwiseInverseMassMatrix<dim, -1, n_components, Number>
63 InverseMassAsMatrixFreeOperator;
64
65 typedef std::pair<unsigned int, unsigned int> Range;
66
67public:
68 InverseMassOperator() : matrix_free(nullptr), dof_index(0), quad_index(0)
69 {
70 }
71
72 void
73 initialize(dealii::MatrixFree<dim, Number> const & matrix_free_in,
74 InverseMassOperatorData const inverse_mass_operator_data)
75 {
76 this->matrix_free = &matrix_free_in;
77 dof_index = inverse_mass_operator_data.dof_index;
78 quad_index = inverse_mass_operator_data.quad_index;
79
80 data = inverse_mass_operator_data.parameters;
81
82 dealii::FiniteElement<dim> const & fe = matrix_free->get_dof_handler(dof_index).get_fe();
83
84 // The inverse mass operator is only available for discontinuous Galerkin discretizations
85 AssertThrow(fe.conforms(dealii::FiniteElementData<dim>::L2),
86 dealii::ExcMessage("InverseMassOperator only implemented for DG!"));
87
88 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
89 {
90 // Currently, the inverse mass realized as matrix-free operator evaluation is only available
91 // in deal.II for tensor-product elements.
92 AssertThrow(
93 fe.base_element(0).dofs_per_cell == dealii::Utilities::pow(fe.degree + 1, dim),
94 dealii::ExcMessage(
95 "The matrix-free inverse mass operator is currently only available for tensor-product elements."));
96
97 // Currently, the inverse mass realized as matrix-free operator evaluation is only available
98 // in deal.II if n_q_points_1d = n_nodes_1d.
99 AssertThrow(
100 this->matrix_free->get_shape_info(0, quad_index).data[0].n_q_points_1d == fe.degree + 1,
101 dealii::ExcMessage(
102 "The matrix-free inverse mass operator is currently only available if n_q_points_1d = n_nodes_1d."));
103 }
104 // We create a block-Jacobi preconditioner with MassOperator as underlying operator in case the
105 // inverse mass can not be realized as a matrix-free operator.
106 else if(data.implementation_type == InverseMassType::ElementwiseKrylovSolver or
107 data.implementation_type == InverseMassType::BlockMatrices)
108 {
109 // initialize mass operator
110 dealii::AffineConstraints<Number> constraint;
111 constraint.clear();
112 constraint.close();
113
114 MassOperatorData<dim> mass_operator_data;
115 mass_operator_data.dof_index = dof_index;
116 mass_operator_data.quad_index = quad_index;
117 if(data.implementation_type == InverseMassType::ElementwiseKrylovSolver)
118 {
119 mass_operator_data.implement_block_diagonal_preconditioner_matrix_free = true;
120 mass_operator_data.solver_block_diagonal = Elementwise::Solver::CG;
121 if(inverse_mass_operator_data.parameters.preconditioner == PreconditionerMass::None)
122 {
123 mass_operator_data.preconditioner_block_diagonal = Elementwise::Preconditioner::None;
124 }
125 else if(inverse_mass_operator_data.parameters.preconditioner ==
126 PreconditionerMass::PointJacobi)
127 {
128 mass_operator_data.preconditioner_block_diagonal =
129 Elementwise::Preconditioner::PointJacobi;
130 }
131 mass_operator_data.solver_data_block_diagonal =
132 inverse_mass_operator_data.parameters.solver_data;
133 }
134
135 mass_operator.initialize(*matrix_free, constraint, mass_operator_data);
136
137 block_jacobi_preconditioner =
138 std::make_shared<BlockJacobiPreconditioner<MassOperator<dim, n_components, Number>>>(
139 mass_operator, true /* initialize_preconditioner */);
140 }
141 else
142 {
143 AssertThrow(false, dealii::ExcMessage("The specified InverseMassType is not implemented."));
144 }
145 }
146
151 void
153 {
154 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
155 {
156 // no updates needed as long as the MatrixFree object is up-to-date (which is not the
157 // responsibility of the present class).
158 }
159 else if(data.implementation_type == InverseMassType::ElementwiseKrylovSolver or
160 data.implementation_type == InverseMassType::BlockMatrices)
161 {
162 // the mass operator does not need to be updated as long as the MatrixFree object is
163 // up-to-date (which is not the responsibility of the present class).
164
165 // update the matrix-based components of the block-Jacobi preconditioner
166 block_jacobi_preconditioner->update();
167 }
168 else
169 {
170 AssertThrow(false, dealii::ExcMessage("The specified InverseMassType is not implemented."));
171 }
172 }
173
174 // dst = M^-1 * src
175 void
176 apply(VectorType & dst, VectorType const & src) const
177 {
178 dst.zero_out_ghost_values();
179
180 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
181 {
182 matrix_free->cell_loop(&This::cell_loop_matrix_free_operator, this, dst, src);
183 }
184 else // ElementwiseKrylovSolver or BlockMatrices
185 {
186 block_jacobi_preconditioner->vmult(dst, src);
187 }
188 }
189
190 // dst = scaling_factor * (M^-1 * src)
191 void
192 apply_scale(VectorType & dst, double const scaling_factor, VectorType const & src) const
193 {
194 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
195 {
196 // In the InverseMassType::MatrixfreeOperator case we can avoid
197 // streaming the vector from memory twice.
198
199 // ghost have to be zeroed out before MatrixFree::cell_loop().
200 dst.zero_out_ghost_values();
201
202 matrix_free->cell_loop(
203 &This::cell_loop_matrix_free_operator,
204 this,
205 dst,
206 src,
207 /*operation before cell operation*/ {}, /*operation after cell operation*/
208 [&](const unsigned int start_range, const unsigned int end_range) {
209 for(unsigned int i = start_range; i < end_range; ++i)
210 dst.local_element(i) *= scaling_factor;
211 },
212 dof_index);
213 }
214 else
215 {
216 apply(dst, src);
217 dst *= scaling_factor;
218 }
219 }
220
221
222private:
223 void
224 cell_loop_matrix_free_operator(dealii::MatrixFree<dim, Number> const &,
225 VectorType & dst,
226 VectorType const & src,
227 Range const & cell_range) const
228 {
229 Integrator integrator(*matrix_free, dof_index, quad_index);
230 InverseMassAsMatrixFreeOperator inverse_mass(integrator);
231
232 for(unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
233 {
234 integrator.reinit(cell);
235 integrator.read_dof_values(src, 0);
236
237 inverse_mass.apply(integrator.begin_dof_values(), integrator.begin_dof_values());
238
239 integrator.set_dof_values(dst, 0);
240 }
241 }
242
243 dealii::MatrixFree<dim, Number> const * matrix_free;
244
245 unsigned int dof_index, quad_index;
246
247 InverseMassParameters data;
248
249 // This variable is only relevant if the inverse mass can not be realized as a matrix-free
250 // operator. Since this class allows only L2-conforming spaces (discontinuous Galerkin method),
251 // the mass matrix is block-diagonal and a block-Jacobi preconditioner inverts the mass operator
252 // exactly (up to solver tolerances). The implementation of the block-Jacobi preconditioner can be
253 // matrix-based or matrix-free, depending on the parameters specified.
254 std::shared_ptr<BlockJacobiPreconditioner<MassOperator<dim, n_components, Number>>>
255 block_jacobi_preconditioner;
256
257 // In case we realize the inverse mass as block-Jacobi preconditioner, we need a MassOperator as
258 // underlying operator for the block-Jacobi preconditioner.
259 MassOperator<dim, n_components, Number> mass_operator;
260};
261
263{
264 InverseMassOperatorDataHdiv() : dof_index(0), quad_index(0)
265 {
266 }
267
268 // Parameters referring to dealii::MatrixFree
269 unsigned int dof_index;
270 unsigned int quad_index;
271
272 InverseMassParametersHdiv parameters;
273};
274
275/*
276 * Inverse mass operator for H(div)-conforming space:
277 *
278 * This class applies the inverse mass operator by solving the mass system as a global linear system
279 * of equations for all degrees of freedom. It is used in case the mass operator is not
280 * block-diagonal and can not be inverted element-wise (e.g. H(div)-conforming space).
281 */
282template<int dim, int n_components, typename Number>
284{
285private:
286 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
287
288public:
289 void
290 initialize(dealii::MatrixFree<dim, Number> const & matrix_free,
291 dealii::AffineConstraints<Number> const & constraints,
292 InverseMassOperatorDataHdiv const inverse_mass_operator_data)
293 {
294 // mass operator
295 MassOperatorData<dim> mass_operator_data;
296 mass_operator_data.dof_index = inverse_mass_operator_data.dof_index;
297 mass_operator_data.quad_index = inverse_mass_operator_data.quad_index;
298 mass_operator.initialize(matrix_free, constraints, mass_operator_data);
299
300 Krylov::SolverDataCG solver_data;
301 solver_data.max_iter = inverse_mass_operator_data.parameters.solver_data.max_iter;
302 solver_data.solver_tolerance_abs = inverse_mass_operator_data.parameters.solver_data.abs_tol;
303 solver_data.solver_tolerance_rel = inverse_mass_operator_data.parameters.solver_data.rel_tol;
304
305 if(inverse_mass_operator_data.parameters.preconditioner == PreconditionerMass::None)
306 {
307 solver_data.use_preconditioner = false;
308 }
309 else if(inverse_mass_operator_data.parameters.preconditioner == PreconditionerMass::PointJacobi)
310 {
311 preconditioner =
312 std::make_shared<JacobiPreconditioner<MassOperator<dim, n_components, Number>>>(
313 mass_operator, true /* initialize_preconditioner */);
314
315 solver_data.use_preconditioner = true;
316 }
317 else
318 {
319 AssertThrow(false, dealii::ExcMessage("Not implemented."));
320 }
321
322 solver =
323 std::make_shared<Krylov::SolverCG<MassOperator<dim, n_components, Number>,
325 VectorType>>(mass_operator, *preconditioner, solver_data);
326 }
327
332 unsigned int
333 apply(VectorType & dst, VectorType const & src) const
334 {
335 Assert(solver.get() != 0, dealii::ExcMessage("Mass solver has not been initialized."));
336
337 VectorType temp;
338
339 // Note that the inverse mass operator might be called like inverse_mass.apply(dst, dst),
340 // i.e. with identical destination and source vectors. In this case, we need to make sure
341 // that the result is still correct.
342 if(&dst == &src)
343 {
344 temp = src;
345 return solver->solve(dst, temp);
346 }
347 else
348 {
349 return solver->solve(dst, src);
350 }
351 }
352
353private:
354 // Solver/preconditioner for mass system solving a global linear system of equations for all
355 // degrees of freedom.
356 std::shared_ptr<PreconditionerBase<Number>> preconditioner;
357 std::shared_ptr<Krylov::SolverBase<VectorType>> solver;
358
359 // We need a MassOperator as underlying operator.
361
363};
364
365} // namespace ExaDG
366
367
368#endif /* INCLUDE_OPERATORS_INVERSEMASSMATRIX_H_ */
Definition inverse_mass_operator.h:284
unsigned int apply(VectorType &dst, VectorType const &src) const
Definition inverse_mass_operator.h:333
Definition inverse_mass_operator.h:53
void update()
Definition inverse_mass_operator.h:152
Definition mass_operator.h:41
Definition preconditioner_base.h:35
Definition driver.cpp:33
Definition inverse_mass_operator.h:263
Definition inverse_mass_operator.h:39
Definition inverse_mass_parameters.h:75
Definition inverse_mass_parameters.h:49
Definition iterative_solvers_dealii_wrapper.h:92
Definition mass_operator.h:33