Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup Linear | ||
10 | * \brief Dumux sequential linear solver backends | ||
11 | */ | ||
12 | #ifndef DUMUX_SEQ_SOLVER_BACKEND_HH | ||
13 | #define DUMUX_SEQ_SOLVER_BACKEND_HH | ||
14 | |||
15 | #include <type_traits> | ||
16 | #include <tuple> | ||
17 | #include <utility> | ||
18 | |||
19 | #include <dune/istl/preconditioners.hh> | ||
20 | #include <dune/istl/solvers.hh> | ||
21 | #include <dune/istl/io.hh> | ||
22 | #include <dune/common/indices.hh> | ||
23 | #include <dune/common/hybridutilities.hh> | ||
24 | |||
25 | #include <dumux/common/parameters.hh> | ||
26 | #include <dumux/common/typetraits/matrix.hh> | ||
27 | #include <dumux/common/typetraits/utility.hh> | ||
28 | #include <dumux/linear/solver.hh> | ||
29 | #include <dumux/linear/preconditioners.hh> | ||
30 | #include <dumux/linear/linearsolverparameters.hh> | ||
31 | #include <dumux/linear/parallelmatrixadapter.hh> | ||
32 | |||
33 | namespace Dumux { | ||
34 | |||
35 | /*! | ||
36 | * \ingroup Linear | ||
37 | * \brief A general solver backend allowing arbitrary preconditioners and solvers. | ||
38 | * | ||
39 | * This class is used as a base class for specific solver-preconditioner | ||
40 | * combinations. Several parameters from the group LinearSolver are read to | ||
41 | * customize the solver and preconditioner: | ||
42 | * | ||
43 | * - Verbosity: determines how verbose the linear solver should print output. | ||
44 | * - MaxIterations: the maximum number of iterations for the linear solver. | ||
45 | * - ResidualReduction: the threshold for declaration of convergence. | ||
46 | * - PreconditionerRelaxation: relaxation parameter for the preconditioner. | ||
47 | * - PreconditionerIterations: usually specifies the number of times the | ||
48 | * preconditioner is applied. In case of ILU(n), | ||
49 | * it specifies the order of the applied ILU. | ||
50 | */ | ||
51 | class IterativePreconditionedSolverImpl | ||
52 | { | ||
53 | public: | ||
54 | |||
55 | // solve with generic parameter tree | ||
56 | template<class Preconditioner, class Solver, class Matrix, class Vector> | ||
57 | static bool solveWithParamTree(const Matrix& A, Vector& x, const Vector& b, | ||
58 | const Dune::ParameterTree& params) | ||
59 | { | ||
60 | // make a linear operator from a matrix | ||
61 | using MatrixAdapter = Dune::MatrixAdapter<Matrix, Vector, Vector>; | ||
62 | const auto linearOperator = std::make_shared<MatrixAdapter>(A); | ||
63 | |||
64 | auto precond = std::make_shared<Preconditioner>(linearOperator, params.sub("preconditioner")); | ||
65 | Solver solver(linearOperator, precond, params); | ||
66 | |||
67 | Vector bTmp(b); | ||
68 | |||
69 | Dune::InverseOperatorResult result; | ||
70 | solver.apply(x, bTmp, result); | ||
71 | |||
72 | return result.converged; | ||
73 | } | ||
74 | }; | ||
75 | |||
76 | /*! | ||
77 | * \ingroup Linear | ||
78 | * \brief Returns the block level for the preconditioner for a given matrix | ||
79 | * | ||
80 | * \tparam M The matrix. | ||
81 | */ | ||
82 | template<class M> | ||
83 | constexpr std::size_t preconditionerBlockLevel() noexcept | ||
84 | { | ||
85 | return isMultiTypeBlockMatrix<M>::value ? 2 : 1; | ||
86 | } | ||
87 | |||
88 | /*! | ||
89 | * \ingroup Linear | ||
90 | * \brief Solver for simple block-diagonal matrices (e.g. from explicit time stepping schemes) | ||
91 | * | ||
92 | * Solver: Single Jacobi iteration | ||
93 | * Preconditioner: Unity | ||
94 | */ | ||
95 |
1/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | class ExplicitDiagonalSolver : public LinearSolver |
96 | { | ||
97 | public: | ||
98 | using LinearSolver::LinearSolver; | ||
99 | |||
100 | template<class Matrix, class Vector> | ||
101 | 2000 | bool solve(const Matrix& A, Vector& x, const Vector& b) | |
102 | { | ||
103 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
2000 | Vector rhs(b); |
104 | 2000 | constexpr auto precondBlockLevel = preconditionerBlockLevel<Matrix>(); | |
105 |
1/2✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
|
4000 | Dune::SeqJac<Matrix, Vector, Vector, precondBlockLevel> jac(A, 1, 1.0); |
106 | jac.pre(x, rhs); | ||
107 | 2000 | jac.apply(x, rhs); | |
108 | 2000 | jac.post(x); | |
109 |
1/2✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
|
4000 | return true; |
110 | } | ||
111 | |||
112 | std::string name() const | ||
113 | { | ||
114 | return "Explicit diagonal matrix solver"; | ||
115 | } | ||
116 | }; | ||
117 | |||
118 | /*! | ||
119 | * \name Solver for MultiTypeBlockMatrix's | ||
120 | */ | ||
121 | // \{ | ||
122 | |||
123 | /*! | ||
124 | * \ingroup Linear | ||
125 | * \brief A Uzawa preconditioned BiCGSTAB solver for saddle-point problems | ||
126 | */ | ||
127 | template <class LinearSolverTraits> | ||
128 | class UzawaBiCGSTABBackend : public LinearSolver | ||
129 | { | ||
130 | public: | ||
131 | using LinearSolver::LinearSolver; | ||
132 | |||
133 | template<class Matrix, class Vector> | ||
134 | bool solve(const Matrix& A, Vector& x, const Vector& b) | ||
135 | { | ||
136 | using Preconditioner = SeqUzawa<Matrix, Vector, Vector>; | ||
137 | using Solver = Dune::BiCGSTABSolver<Vector>; | ||
138 | static const auto solverParams = LinearSolverParameters<LinearSolverTraits>::createParameterTree(this->paramGroup()); | ||
139 | return IterativePreconditionedSolverImpl::template solveWithParamTree<Preconditioner, Solver>(A, x, b, solverParams); | ||
140 | } | ||
141 | |||
142 | std::string name() const | ||
143 | { | ||
144 | return "Uzawa preconditioned BiCGSTAB solver"; | ||
145 | } | ||
146 | }; | ||
147 | |||
148 | /*! | ||
149 | * \ingroup Linear | ||
150 | * \brief A simple ilu0 block diagonal preconditioner | ||
151 | */ | ||
152 | template<class M, class X, class Y, int blockLevel = 2> | ||
153 | 1498 | class BlockDiagILU0Preconditioner : public Dune::Preconditioner<X, Y> | |
154 | { | ||
155 | template<std::size_t i> | ||
156 | using DiagBlockType = std::decay_t<decltype(std::declval<M>()[Dune::index_constant<i>{}][Dune::index_constant<i>{}])>; | ||
157 | |||
158 | template<std::size_t i> | ||
159 | using VecBlockType = std::decay_t<decltype(std::declval<X>()[Dune::index_constant<i>{}])>; | ||
160 | |||
161 | template<std::size_t i> | ||
162 | using BlockILU = Dune::SeqILU<DiagBlockType<i>, VecBlockType<i>, VecBlockType<i>, blockLevel-1>; | ||
163 | |||
164 | using ILUTuple = typename makeFromIndexedType<std::tuple, BlockILU, std::make_index_sequence<M::N()> >::type; | ||
165 | |||
166 | public: | ||
167 | //! \brief The matrix type the preconditioner is for. | ||
168 | using matrix_type = typename std::decay_t<M>; | ||
169 | //! \brief The domain type of the preconditioner. | ||
170 | using domain_type = X; | ||
171 | //! \brief The range type of the preconditioner. | ||
172 | using range_type = Y; | ||
173 | //! \brief The field type of the preconditioner. | ||
174 | using field_type = typename X::field_type; | ||
175 | |||
176 | /*! \brief Constructor. | ||
177 | |||
178 | Constructor gets all parameters to operate the prec. | ||
179 | \param m The (multi type block) matrix to operate on | ||
180 | \param w The relaxation factor | ||
181 | */ | ||
182 | 749 | BlockDiagILU0Preconditioner(const M& m, double w = 1.0) | |
183 | 749 | : BlockDiagILU0Preconditioner(m, w, std::make_index_sequence<M::N()>{}) | |
184 | { | ||
185 | static_assert(blockLevel >= 2, "Only makes sense for MultiTypeBlockMatrix!"); | ||
186 | } | ||
187 | |||
188 | 749 | void pre (X& v, Y& d) final {} | |
189 | |||
190 | 68746 | void apply (X& v, const Y& d) final | |
191 | { | ||
192 | using namespace Dune::Hybrid; | ||
193 | 68746 | forEach(integralRange(Dune::Hybrid::size(ilu_)), [&](const auto i) | |
194 | { | ||
195 | ✗ | std::get<decltype(i)::value>(ilu_).apply(v[i], d[i]); | |
196 | }); | ||
197 | 68746 | } | |
198 | |||
199 | 749 | void post (X&) final {} | |
200 | |||
201 | //! Category of the preconditioner (see SolverCategory::Category) | ||
202 | 749 | Dune::SolverCategory::Category category() const final | |
203 | { | ||
204 | 749 | return Dune::SolverCategory::sequential; | |
205 | } | ||
206 | |||
207 | private: | ||
208 | template<std::size_t... Is> | ||
209 | 749 | BlockDiagILU0Preconditioner (const M& m, double w, std::index_sequence<Is...> is) | |
210 |
3/6✓ Branch 4 taken 749 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 749 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 749 times.
✗ Branch 11 not taken.
|
2996 | : ilu_(std::make_tuple(BlockILU<Is>(m[Dune::index_constant<Is>{}][Dune::index_constant<Is>{}], w)...)) |
211 | 749 | {} | |
212 | |||
213 | ILUTuple ilu_; | ||
214 | }; | ||
215 | |||
216 | |||
217 | /*! | ||
218 | * \ingroup Linear | ||
219 | * \brief A simple ilu0 block diagonal preconditioned BiCGSTABSolver | ||
220 | * \note expects a system as a multi-type block-matrix | ||
221 | * | A B | | ||
222 | * | C D | | ||
223 | */ | ||
224 |
1/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 26 times.
|
26 | class BlockDiagILU0BiCGSTABSolver : public LinearSolver |
225 | { | ||
226 | |||
227 | public: | ||
228 | using LinearSolver::LinearSolver; | ||
229 | |||
230 | template<class Matrix, class Vector> | ||
231 | 749 | bool solve(const Matrix& M, Vector& x, const Vector& b) | |
232 | { | ||
233 | 749 | BlockDiagILU0Preconditioner<Matrix, Vector, Vector> preconditioner(M); | |
234 |
1/4✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1498 | Dumux::ParallelMultiTypeMatrixAdapter<Matrix, Vector, Vector> op(M); |
235 |
5/10✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 749 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 749 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 749 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 749 times.
✗ Branch 13 not taken.
|
3745 | Dune::BiCGSTABSolver<Vector> solver(op, preconditioner, this->residReduction(), |
236 | this->maxIter(), this->verbosity()); | ||
237 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
1498 | auto bTmp(b); |
238 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | solver.apply(x, bTmp, result_); |
239 | |||
240 | 1498 | return result_.converged; | |
241 | } | ||
242 | |||
243 | const Dune::InverseOperatorResult& result() const | ||
244 | { | ||
245 | return result_; | ||
246 | } | ||
247 | |||
248 | ✗ | std::string name() const | |
249 |
6/16✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 19 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 19 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
40 | { return "block-diagonal ILU0-preconditioned BiCGSTAB solver"; } |
250 | |||
251 | private: | ||
252 | Dune::InverseOperatorResult result_; | ||
253 | }; | ||
254 | |||
255 | /*! | ||
256 | * \ingroup Linear | ||
257 | * \brief A simple ilu0 block diagonal preconditioned RestartedGMResSolver | ||
258 | * \note expects a system as a multi-type block-matrix | ||
259 | * | A B | | ||
260 | * | C D | | ||
261 | */ | ||
262 | class BlockDiagILU0RestartedGMResSolver : public LinearSolver | ||
263 | { | ||
264 | |||
265 | public: | ||
266 | using LinearSolver::LinearSolver; | ||
267 | |||
268 | template<int precondBlockLevel = 2, class Matrix, class Vector> | ||
269 | bool solve(const Matrix& M, Vector& x, const Vector& b) | ||
270 | { | ||
271 | BlockDiagILU0Preconditioner<Matrix, Vector, Vector> preconditioner(M); | ||
272 | Dumux::ParallelMultiTypeMatrixAdapter<Matrix, Vector, Vector> op(M); | ||
273 | static const int restartGMRes = getParamFromGroup<int>(this->paramGroup(), "LinearSolver.GMResRestart"); | ||
274 | Dune::RestartedGMResSolver<Vector> solver(op, preconditioner, this->residReduction(), restartGMRes, | ||
275 | this->maxIter(), this->verbosity()); | ||
276 | auto bTmp(b); | ||
277 | solver.apply(x, bTmp, result_); | ||
278 | |||
279 | return result_.converged; | ||
280 | } | ||
281 | |||
282 | const Dune::InverseOperatorResult& result() const | ||
283 | { | ||
284 | return result_; | ||
285 | } | ||
286 | |||
287 | std::string name() const | ||
288 | { return "block-diagonal ILU0-preconditioned restarted GMRes solver"; } | ||
289 | |||
290 | private: | ||
291 | Dune::InverseOperatorResult result_; | ||
292 | }; | ||
293 | |||
294 | /*! | ||
295 | * \ingroup Linear | ||
296 | * \brief A simple ilu0 block diagonal preconditioner | ||
297 | */ | ||
298 | template<class M, class X, class Y, int blockLevel = 2> | ||
299 | 3080 | class BlockDiagAMGPreconditioner : public Dune::Preconditioner<X, Y> | |
300 | { | ||
301 | template<std::size_t i> | ||
302 | using DiagBlockType = std::decay_t<decltype(std::declval<M>()[Dune::index_constant<i>{}][Dune::index_constant<i>{}])>; | ||
303 | |||
304 | template<std::size_t i> | ||
305 | using VecBlockType = std::decay_t<decltype(std::declval<X>()[Dune::index_constant<i>{}])>; | ||
306 | |||
307 | template<std::size_t i> | ||
308 | using Smoother = Dune::SeqSSOR<DiagBlockType<i>, VecBlockType<i>, VecBlockType<i>>; | ||
309 | |||
310 | template<std::size_t i> | ||
311 | using LinearOperator = Dune::MatrixAdapter<DiagBlockType<i>, VecBlockType<i>, VecBlockType<i>>; | ||
312 | |||
313 | template<std::size_t i> | ||
314 | using ScalarProduct = Dune::SeqScalarProduct<VecBlockType<i>>; | ||
315 | |||
316 | template<std::size_t i> | ||
317 | using BlockAMG = Dune::Amg::AMG<LinearOperator<i>, VecBlockType<i>, Smoother<i>>; | ||
318 | |||
319 | using AMGTuple = typename makeFromIndexedType<std::tuple, BlockAMG, std::make_index_sequence<M::N()> >::type; | ||
320 | |||
321 | public: | ||
322 | //! \brief The matrix type the preconditioner is for. | ||
323 | using matrix_type = typename std::decay_t<M>; | ||
324 | //! \brief The domain type of the preconditioner. | ||
325 | using domain_type = X; | ||
326 | //! \brief The range type of the preconditioner. | ||
327 | using range_type = Y; | ||
328 | //! \brief The field type of the preconditioner. | ||
329 | using field_type = typename X::field_type; | ||
330 | |||
331 | /*! \brief Constructor. | ||
332 | |||
333 | Constructor gets all parameters to operate the prec. | ||
334 | \param lop The linear operator | ||
335 | \param c The criterion | ||
336 | \param sa The smoother arguments | ||
337 | */ | ||
338 | template<class LOP, class Criterion, class SmootherArgs> | ||
339 | 1540 | BlockDiagAMGPreconditioner(const LOP& lop, const Criterion& c, const SmootherArgs& sa) | |
340 | 1540 | : BlockDiagAMGPreconditioner(lop, c, sa, std::make_index_sequence<M::N()>{}) | |
341 | { | ||
342 | static_assert(blockLevel >= 2, "Only makes sense for MultiTypeBlockMatrix!"); | ||
343 | } | ||
344 | |||
345 | /*! | ||
346 | * \brief Prepare the preconditioner. | ||
347 | * | ||
348 | * A solver solves a linear operator equation A(v)=d by applying | ||
349 | * one or several steps of the preconditioner. The method pre() | ||
350 | * is called before the first apply operation. | ||
351 | * d and v are right hand side and solution vector of the linear | ||
352 | * system respectively. It may. e.g., scale the system, allocate memory or | ||
353 | * compute a (I)LU decomposition. | ||
354 | * Note: The ILU decomposition could also be computed in the constructor | ||
355 | * or with a separate method of the derived method if several | ||
356 | * linear systems with the same matrix are to be solved. | ||
357 | * | ||
358 | * \param v The left hand side of the equation. | ||
359 | * \param d The right hand side of the equation. | ||
360 | */ | ||
361 | 1540 | void pre (X& v, Y& d) final | |
362 | { | ||
363 | using namespace Dune::Hybrid; | ||
364 | 1540 | forEach(integralRange(Dune::Hybrid::size(amg_)), [&](const auto i) | |
365 | { | ||
366 | ✗ | std::get<decltype(i)::value>(amg_).pre(v[i], d[i]); | |
367 | }); | ||
368 | 1540 | } | |
369 | |||
370 | /*! | ||
371 | * \brief Apply one step of the preconditioner to the system A(v)=d. | ||
372 | * | ||
373 | * On entry v=0 and d=b-A(x) (although this might not be | ||
374 | * computed in that way. On exit v contains the update, i.e | ||
375 | * one step computes \f$ v = M^{-1} d \f$ where \f$ M \f$ is the | ||
376 | * approximate inverse of the operator \f$ A \f$ characterizing | ||
377 | * the preconditioner. | ||
378 | * \param v The update to be computed | ||
379 | * \param d The current defect. | ||
380 | */ | ||
381 | 2509 | void apply (X& v, const Y& d) final | |
382 | { | ||
383 | using namespace Dune::Hybrid; | ||
384 | 2509 | forEach(integralRange(Dune::Hybrid::size(amg_)), [&](const auto i) | |
385 | { | ||
386 | ✗ | std::get<decltype(i)::value>(amg_).apply(v[i], d[i]); | |
387 | }); | ||
388 | 2509 | } | |
389 | |||
390 | /*! | ||
391 | * \brief Clean up. | ||
392 | * | ||
393 | * This method is called after the last apply call for the | ||
394 | * linear system to be solved. Memory may be deallocated safely | ||
395 | * here. v is the solution of the linear equation. | ||
396 | * | ||
397 | * \param v The right hand side of the equation. | ||
398 | */ | ||
399 | 1540 | void post (X& v) final | |
400 | { | ||
401 | using namespace Dune::Hybrid; | ||
402 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
1540 | forEach(integralRange(Dune::Hybrid::size(amg_)), [&](const auto i) |
403 | { | ||
404 |
6/36✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✓ Branch 49 taken 1540 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 1540 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 1540 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 1540 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 1540 times.
✗ Branch 62 not taken.
✓ Branch 64 taken 1540 times.
✗ Branch 65 not taken.
|
4620 | std::get<decltype(i)::value>(amg_).post(v[i]); |
405 | }); | ||
406 | 1540 | } | |
407 | |||
408 | //! Category of the preconditioner (see SolverCategory::Category) | ||
409 | 1540 | Dune::SolverCategory::Category category() const final | |
410 | { | ||
411 | 1540 | return Dune::SolverCategory::sequential; | |
412 | } | ||
413 | |||
414 | private: | ||
415 | template<class LOP, class Criterion, class SmootherArgs, std::size_t... Is> | ||
416 | 1540 | BlockDiagAMGPreconditioner (const LOP& lop, const Criterion& c, const SmootherArgs& sa, std::index_sequence<Is...> is) | |
417 |
8/16✓ Branch 9 taken 1540 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1540 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 1540 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1540 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1540 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 1540 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 1540 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 1540 times.
✗ Branch 31 not taken.
|
13860 | : amg_(std::make_tuple(BlockAMG<Is>(*std::get<Is>(lop), *std::get<Is>(c), *std::get<Is>(sa))...)) |
418 | 1540 | {} | |
419 | |||
420 | AMGTuple amg_; | ||
421 | }; | ||
422 | |||
423 | /*! | ||
424 | * \ingroup Linear | ||
425 | * \brief A simple ilu0 block diagonal preconditioned BiCGSTABSolver | ||
426 | * \note expects a system as a multi-type block-matrix | ||
427 | * | A B | | ||
428 | * | C D | | ||
429 | */ | ||
430 |
1/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | class BlockDiagAMGBiCGSTABSolver : public LinearSolver |
431 | { | ||
432 | template<class M, std::size_t i> | ||
433 | using DiagBlockType = std::decay_t<decltype(std::declval<M>()[Dune::index_constant<i>{}][Dune::index_constant<i>{}])>; | ||
434 | |||
435 | template<class X, std::size_t i> | ||
436 | using VecBlockType = std::decay_t<decltype(std::declval<X>()[Dune::index_constant<i>{}])>; | ||
437 | |||
438 | template<class M, class X, std::size_t i> | ||
439 | using Smoother = Dune::SeqSSOR<DiagBlockType<M, i>, VecBlockType<X, i>, VecBlockType<X, i>>; | ||
440 | |||
441 | template<class M, class X, std::size_t i> | ||
442 | using SmootherArgs = typename Dune::Amg::SmootherTraits<Smoother<M, X, i>>::Arguments; | ||
443 | |||
444 | template<class M, std::size_t i> | ||
445 | using Criterion = Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<DiagBlockType<M, i>, Dune::Amg::FirstDiagonal>>; | ||
446 | |||
447 | template<class M, class X, std::size_t i> | ||
448 | using LinearOperator = Dune::MatrixAdapter<DiagBlockType<M, i>, VecBlockType<X, i>, VecBlockType<X, i>>; | ||
449 | |||
450 | public: | ||
451 | using LinearSolver::LinearSolver; | ||
452 | |||
453 | // Solve saddle-point problem using a Schur complement based preconditioner | ||
454 | template<class Matrix, class Vector> | ||
455 | 1540 | bool solve(const Matrix& m, Vector& x, const Vector& b) | |
456 | { | ||
457 | //! \todo Check whether the default accumulation mode atOnceAccu is needed. | ||
458 | //! \todo make parameters changeable at runtime from input file / parameter tree | ||
459 | 1540 | Dune::Amg::Parameters params(15, 2000, 1.2, 1.6, Dune::Amg::atOnceAccu); | |
460 | 1540 | params.setDefaultValuesIsotropic(3); | |
461 | 3080 | params.setDebugLevel(this->verbosity()); | |
462 | |||
463 | 1540 | auto criterion = makeCriterion_<Criterion, Matrix>(params, std::make_index_sequence<Matrix::N()>{}); | |
464 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
3080 | auto smootherArgs = makeSmootherArgs_<SmootherArgs, Matrix, Vector>(std::make_index_sequence<Matrix::N()>{}); |
465 | |||
466 | using namespace Dune::Hybrid; | ||
467 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
1540 | forEach(std::make_index_sequence<Matrix::N()>{}, [&](const auto i) |
468 | { | ||
469 |
2/4✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1540 times.
✗ Branch 5 not taken.
|
3080 | auto& args = std::get<decltype(i)::value>(smootherArgs); |
470 |
2/4✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1540 times.
✗ Branch 5 not taken.
|
3080 | args->iterations = 1; |
471 |
4/8✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1540 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1540 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1540 times.
✗ Branch 11 not taken.
|
6160 | args->relaxationFactor = 1; |
472 | }); | ||
473 | |||
474 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
3080 | auto linearOperator = makeLinearOperator_<LinearOperator, Matrix, Vector>(m, std::make_index_sequence<Matrix::N()>{}); |
475 | |||
476 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
3080 | BlockDiagAMGPreconditioner<Matrix, Vector, Vector> preconditioner(linearOperator, criterion, smootherArgs); |
477 | |||
478 |
1/4✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3080 | Dumux::ParallelMultiTypeMatrixAdapter<Matrix, Vector, Vector> op(m); |
479 |
5/10✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1540 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1540 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1540 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1540 times.
✗ Branch 13 not taken.
|
7700 | Dune::BiCGSTABSolver<Vector> solver(op, preconditioner, this->residReduction(), |
480 | this->maxIter(), this->verbosity()); | ||
481 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
3080 | auto bTmp(b); |
482 |
1/2✓ Branch 1 taken 1540 times.
✗ Branch 2 not taken.
|
1540 | solver.apply(x, bTmp, result_); |
483 | |||
484 | 3080 | return result_.converged; | |
485 | } | ||
486 | |||
487 | const Dune::InverseOperatorResult& result() const | ||
488 | { | ||
489 | return result_; | ||
490 | } | ||
491 | |||
492 | std::string name() const | ||
493 | { return "block-diagonal AMG-preconditioned BiCGSTAB solver"; } | ||
494 | |||
495 | private: | ||
496 | template<template<class M, std::size_t i> class Criterion, class Matrix, class Params, std::size_t... Is> | ||
497 | 1540 | auto makeCriterion_(const Params& p, std::index_sequence<Is...>) | |
498 | { | ||
499 |
1/4✓ Branch 2 taken 1540 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1540 | return std::make_tuple(std::make_shared<Criterion<Matrix, Is>>(p)...); |
500 | } | ||
501 | |||
502 | template<template<class M, class X, std::size_t i> class SmootherArgs, class Matrix, class Vector, std::size_t... Is> | ||
503 | 1540 | auto makeSmootherArgs_(std::index_sequence<Is...>) | |
504 | { | ||
505 |
1/4✓ Branch 2 taken 1540 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1540 | return std::make_tuple(std::make_shared<SmootherArgs<Matrix, Vector, Is>>()...); |
506 | } | ||
507 | |||
508 | template<template<class M, class X, std::size_t i> class LinearOperator, class Matrix, class Vector, std::size_t... Is> | ||
509 | 1540 | auto makeLinearOperator_(const Matrix& m, std::index_sequence<Is...>) | |
510 | { | ||
511 |
3/8✓ Branch 4 taken 1540 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1540 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1540 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
4620 | return std::make_tuple(std::make_shared<LinearOperator<Matrix, Vector, Is>>(m[Dune::index_constant<Is>{}][Dune::index_constant<Is>{}])...); |
512 | } | ||
513 | |||
514 | Dune::InverseOperatorResult result_; | ||
515 | }; | ||
516 | |||
517 | // \} | ||
518 | |||
519 | } // end namespace Dumux | ||
520 | |||
521 | #endif | ||
522 |