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-FileCopyrightText: 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 Linear solvers from dune-istl | ||
11 | */ | ||
12 | #ifndef DUMUX_LINEAR_ISTL_SOLVERS_HH | ||
13 | #define DUMUX_LINEAR_ISTL_SOLVERS_HH | ||
14 | |||
15 | #include <memory> | ||
16 | #include <variant> | ||
17 | |||
18 | #include <dune/common/exceptions.hh> | ||
19 | #include <dune/common/shared_ptr.hh> | ||
20 | #include <dune/common/version.hh> | ||
21 | #include <dune/common/parallel/indexset.hh> | ||
22 | #include <dune/common/parallel/mpicommunication.hh> | ||
23 | #include <dune/grid/common/capabilities.hh> | ||
24 | #include <dune/istl/solvers.hh> | ||
25 | #include <dune/istl/solverfactory.hh> | ||
26 | #include <dune/istl/owneroverlapcopy.hh> | ||
27 | #include <dune/istl/scalarproducts.hh> | ||
28 | #include <dune/istl/paamg/amg.hh> | ||
29 | #include <dune/istl/paamg/pinfo.hh> | ||
30 | |||
31 | #include <dumux/common/typetraits/matrix.hh> | ||
32 | #include <dumux/common/typetraits/vector.hh> | ||
33 | #include <dumux/linear/linearalgebratraits.hh> | ||
34 | #include <dumux/linear/preconditioners.hh> | ||
35 | #include <dumux/linear/linearsolverparameters.hh> | ||
36 | #include <dumux/linear/matrixconverter.hh> | ||
37 | #include <dumux/linear/parallelhelpers.hh> | ||
38 | #include <dumux/linear/solvercategory.hh> | ||
39 | #include <dumux/linear/solver.hh> | ||
40 | |||
41 | #include <dune/istl/foreach.hh> | ||
42 | |||
43 | namespace Dumux::Detail::IstlSolvers { | ||
44 | |||
45 | /*! | ||
46 | * \ingroup Linear | ||
47 | * \brief Returns the block level for the preconditioner for a given matrix | ||
48 | * | ||
49 | * \tparam M The matrix. | ||
50 | */ | ||
51 | template<class M> | ||
52 | constexpr std::size_t preconditionerBlockLevel() noexcept | ||
53 | { | ||
54 | return isMultiTypeBlockMatrix<M>::value ? 2 : 1; | ||
55 | } | ||
56 | |||
57 | template<template<class,class,class,int> class Preconditioner, int blockLevel = 1> | ||
58 | class IstlDefaultBlockLevelPreconditionerFactory | ||
59 | { | ||
60 | public: | ||
61 | template<class TL, class M> | ||
62 | 19466 | auto operator() (TL typeList, const M& matrix, const Dune::ParameterTree& config) | |
63 | { | ||
64 | using Matrix = typename Dune::TypeListElement<0, decltype(typeList)>::type; | ||
65 | using Domain = typename Dune::TypeListElement<1, decltype(typeList)>::type; | ||
66 | using Range = typename Dune::TypeListElement<2, decltype(typeList)>::type; | ||
67 |
4/8✓ Branch 1 taken 978 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2464 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15988 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 36 times.
✗ Branch 11 not taken.
|
19466 | std::shared_ptr<Dune::Preconditioner<Domain, Range>> preconditioner |
68 | = std::make_shared<Preconditioner<Matrix, Domain, Range, blockLevel>>(matrix, config); | ||
69 | return preconditioner; | ||
70 | } | ||
71 | }; | ||
72 | |||
73 | template<template<class,class,class> class Preconditioner> | ||
74 | class IstlDefaultPreconditionerFactory | ||
75 | { | ||
76 | template<class TL, class M> | ||
77 | auto operator() (TL typeList, const M& matrix, const Dune::ParameterTree& config) | ||
78 | { | ||
79 | using Matrix = typename Dune::TypeListElement<0, decltype(typeList)>::type; | ||
80 | using Domain = typename Dune::TypeListElement<1, decltype(typeList)>::type; | ||
81 | using Range = typename Dune::TypeListElement<2, decltype(typeList)>::type; | ||
82 | std::shared_ptr<Dune::Preconditioner<Domain, Range>> preconditioner | ||
83 | = std::make_shared<Preconditioner<Matrix, Domain, Range>>(matrix, config); | ||
84 | return preconditioner; | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | using IstlAmgPreconditionerFactory = Dune::AMGCreator; | ||
89 | |||
90 | template<class M, bool convert = false> | ||
91 | struct MatrixForSolver { using type = M; }; | ||
92 | |||
93 | template<class M> | ||
94 | struct MatrixForSolver<M, true> | ||
95 | { using type = std::decay_t<decltype(MatrixConverter<M>::multiTypeToBCRSMatrix(std::declval<M>()))>; }; | ||
96 | |||
97 | template<class V, bool convert = false> | ||
98 | struct VectorForSolver { using type = V; }; | ||
99 | |||
100 | template<class V> | ||
101 | struct VectorForSolver<V, true> | ||
102 | { using type = std::decay_t<decltype(VectorConverter<V>::multiTypeToBlockVector(std::declval<V>()))>; }; | ||
103 | |||
104 | template<class LSTraits, class LATraits, bool convert, bool parallel = LSTraits::canCommunicate> | ||
105 | struct MatrixOperator; | ||
106 | |||
107 | template<class LSTraits, class LATraits, bool convert> | ||
108 | struct MatrixOperator<LSTraits, LATraits, convert, true> | ||
109 | { | ||
110 | using M = typename MatrixForSolver<typename LATraits::Matrix, convert>::type; | ||
111 | using V = typename VectorForSolver<typename LATraits::Vector, convert>::type; | ||
112 | #if HAVE_MPI | ||
113 | using type = std::variant< | ||
114 | std::shared_ptr<typename LSTraits::template Sequential<M, V>::LinearOperator>, | ||
115 | std::shared_ptr<typename LSTraits::template ParallelOverlapping<M, V>::LinearOperator>, | ||
116 | std::shared_ptr<typename LSTraits::template ParallelNonoverlapping<M, V>::LinearOperator> | ||
117 | >; | ||
118 | #else | ||
119 | using type = std::variant< | ||
120 | std::shared_ptr<typename LSTraits::template Sequential<M, V>::LinearOperator> | ||
121 | >; | ||
122 | #endif | ||
123 | }; | ||
124 | |||
125 | template<class LSTraits, class LATraits, bool convert> | ||
126 | struct MatrixOperator<LSTraits, LATraits, convert, false> | ||
127 | { | ||
128 | using M = typename MatrixForSolver<typename LATraits::Matrix, convert>::type; | ||
129 | using V = typename VectorForSolver<typename LATraits::Vector, convert>::type; | ||
130 | using type = std::variant< | ||
131 | std::shared_ptr<typename LSTraits::template Sequential<M, V>::LinearOperator> | ||
132 | >; | ||
133 | }; | ||
134 | |||
135 | } // end namespace Dumux::Detail::IstlSolvers | ||
136 | |||
137 | namespace Dumux::Detail { | ||
138 | |||
139 | struct IstlSolverResult : public Dune::InverseOperatorResult | ||
140 | { | ||
141 | IstlSolverResult() = default; | ||
142 | IstlSolverResult(const IstlSolverResult&) = default; | ||
143 | IstlSolverResult(IstlSolverResult&&) = default; | ||
144 | |||
145 | IstlSolverResult(const Dune::InverseOperatorResult& o) : InverseOperatorResult(o) {} | ||
146 | 62756 | IstlSolverResult(Dune::InverseOperatorResult&& o) : InverseOperatorResult(std::move(o)) {} | |
147 | |||
148 | 62147 | operator bool() const { return this->converged; } | |
149 | }; | ||
150 | |||
151 | /*! | ||
152 | * \ingroup Linear | ||
153 | * \brief Standard dune-istl iterative linear solvers | ||
154 | */ | ||
155 | template<class LinearSolverTraits, class LinearAlgebraTraits, | ||
156 | class InverseOperator, class PreconditionerFactory, | ||
157 | bool convertMultiTypeLATypes = false> | ||
158 | class IstlIterativeLinearSolver | ||
159 | { | ||
160 | using Matrix = typename LinearAlgebraTraits::Matrix; | ||
161 | using XVector = typename LinearAlgebraTraits::Vector; | ||
162 | using BVector = typename LinearAlgebraTraits::Vector; | ||
163 | using Scalar = typename InverseOperator::real_type; | ||
164 | |||
165 | using ScalarProduct = Dune::ScalarProduct<typename InverseOperator::domain_type>; | ||
166 | |||
167 | static constexpr bool convertMultiTypeVectorAndMatrix | ||
168 | = convertMultiTypeLATypes && isMultiTypeBlockVector<XVector>::value; | ||
169 | using MatrixForSolver = typename Detail::IstlSolvers::MatrixForSolver<Matrix, convertMultiTypeVectorAndMatrix>::type; | ||
170 | using BVectorForSolver = typename Detail::IstlSolvers::VectorForSolver<BVector, convertMultiTypeVectorAndMatrix>::type; | ||
171 | using XVectorForSolver = typename Detail::IstlSolvers::VectorForSolver<XVector, convertMultiTypeVectorAndMatrix>::type; | ||
172 | // a variant type that can hold sequential, overlapping, and non-overlapping operators | ||
173 | using MatrixOperatorHolder = typename Detail::IstlSolvers::MatrixOperator< | ||
174 | LinearSolverTraits, LinearAlgebraTraits, convertMultiTypeVectorAndMatrix | ||
175 | >::type; | ||
176 | |||
177 | #if HAVE_MPI | ||
178 | using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>; | ||
179 | using ParallelHelper = ParallelISTLHelper<LinearSolverTraits>; | ||
180 | #endif | ||
181 | |||
182 | using ParameterInitializer = std::variant<std::string, Dune::ParameterTree>; | ||
183 | public: | ||
184 | |||
185 | /*! | ||
186 | * \brief Constructor for sequential solvers | ||
187 | */ | ||
188 | 97 | IstlIterativeLinearSolver(const ParameterInitializer& params = "") | |
189 | 97 | { | |
190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | if (Dune::MPIHelper::getCommunication().size() > 1) |
191 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Using sequential constructor for parallel run. Use signature with gridView and dofMapper!"); | |
192 | |||
193 |
1/2✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
|
97 | initializeParameters_(params); |
194 |
1/2✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
|
97 | solverCategory_ = Dune::SolverCategory::sequential; |
195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | scalarProduct_ = std::make_shared<ScalarProduct>(); |
196 | 97 | } | |
197 | |||
198 | /*! | ||
199 | * \brief Constructor for parallel and sequential solvers | ||
200 | */ | ||
201 | template <class GridView, class DofMapper> | ||
202 | 288 | IstlIterativeLinearSolver(const GridView& gridView, | |
203 | const DofMapper& dofMapper, | ||
204 | const ParameterInitializer& params = "") | ||
205 | 288 | { | |
206 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
|
527 | initializeParameters_(params, gridView.comm()); |
207 | #if HAVE_MPI | ||
208 |
1/2✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
288 | solverCategory_ = Detail::solverCategory<LinearSolverTraits>(gridView); |
209 | if constexpr (LinearSolverTraits::canCommunicate) | ||
210 | { | ||
211 | |||
212 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 238 times.
|
264 | if (solverCategory_ != Dune::SolverCategory::sequential) |
213 | { | ||
214 |
2/5✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
22 | parallelHelper_ = std::make_shared<ParallelISTLHelper<LinearSolverTraits>>(gridView, dofMapper); |
215 |
8/10✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 14 times.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 7 taken 8 times.
|
22 | communication_ = std::make_shared<Comm>(gridView.comm(), solverCategory_); |
216 |
3/6✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
|
22 | scalarProduct_ = Dune::createScalarProduct<XVector>(*communication_, solverCategory_); |
217 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | parallelHelper_->createParallelIndexSet(*communication_); |
218 | } | ||
219 | else | ||
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 238 times.
|
242 | scalarProduct_ = std::make_shared<ScalarProduct>(); |
221 | } | ||
222 | else | ||
223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | scalarProduct_ = std::make_shared<ScalarProduct>(); |
224 | #else | ||
225 | solverCategory_ = Dune::SolverCategory::sequential; | ||
226 | scalarProduct_ = std::make_shared<ScalarProduct>(); | ||
227 | #endif | ||
228 | 288 | } | |
229 | |||
230 | #if HAVE_MPI | ||
231 | /*! | ||
232 | * \brief Constructor with custom scalar product and communication | ||
233 | */ | ||
234 | template <class GridView, class DofMapper> | ||
235 | IstlIterativeLinearSolver(std::shared_ptr<Comm> communication, | ||
236 | std::shared_ptr<ScalarProduct> scalarProduct, | ||
237 | const GridView& gridView, | ||
238 | const DofMapper& dofMapper, | ||
239 | const ParameterInitializer& params = "") | ||
240 | { | ||
241 | initializeParameters_(params, gridView.comm()); | ||
242 | solverCategory_ = Detail::solverCategory(gridView); | ||
243 | scalarProduct_ = scalarProduct; | ||
244 | communication_ = communication; | ||
245 | if constexpr (LinearSolverTraits::canCommunicate) | ||
246 | { | ||
247 | if (solverCategory_ != Dune::SolverCategory::sequential) | ||
248 | { | ||
249 | parallelHelper_ = std::make_shared<ParallelISTLHelper<LinearSolverTraits>>(gridView, dofMapper); | ||
250 | parallelHelper_->createParallelIndexSet(communication); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | #endif | ||
255 | |||
256 | /*! | ||
257 | * \brief Solve the linear system Ax = b | ||
258 | */ | ||
259 | 34950 | IstlSolverResult solve(Matrix& A, XVector& x, BVector& b) | |
260 | 34949 | { return solveSequentialOrParallel_(A, x, b); } | |
261 | |||
262 | /*! | ||
263 | * \brief Set the matrix A of the linear system Ax = b for reuse | ||
264 | */ | ||
265 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | void setMatrix(std::shared_ptr<Matrix> A) |
266 | { | ||
267 |
3/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 31 times.
|
65 | linearOperator_ = makeParallelOrSequentialLinearOperator_(std::move(A)); |
268 | 34 | solver_ = constructPreconditionedSolver_(linearOperator_); | |
269 | 34 | } | |
270 | |||
271 | /*! | ||
272 | * \brief Set the matrix A of the linear system Ax = b for reuse | ||
273 | * \note The client has to take care of the lifetime management of A | ||
274 | */ | ||
275 | 3 | void setMatrix(Matrix& A) | |
276 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | { setMatrix(Dune::stackobject_to_shared_ptr(A)); } |
277 | |||
278 | /*! | ||
279 | * \brief Solve the linear system Ax = b where A has been set with \ref setMatrix | ||
280 | */ | ||
281 | 181 | IstlSolverResult solve(XVector& x, BVector& b) const | |
282 | { | ||
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
|
181 | if (!solver_) |
284 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Called solve(x, b) but no linear operator has been set"); | |
285 | |||
286 | 181 | return solveSequentialOrParallel_(x, b, *solver_); | |
287 | } | ||
288 | |||
289 | /*! | ||
290 | * \brief Compute the 2-norm of vector x | ||
291 | */ | ||
292 | 9374 | Scalar norm(const XVector& x) const | |
293 | { | ||
294 | #if HAVE_MPI | ||
295 | if constexpr (LinearSolverTraits::canCommunicate) | ||
296 | { | ||
297 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 8580 times.
|
8692 | if (solverCategory_ == Dune::SolverCategory::nonoverlapping) |
298 | { | ||
299 | 112 | auto y(x); // make a copy because the vector needs to be made consistent | |
300 | using GV = typename LinearSolverTraits::GridView; | ||
301 | using DM = typename LinearSolverTraits::DofMapper; | ||
302 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
112 | ParallelVectorHelper<GV, DM, LinearSolverTraits::dofCodim> vectorHelper(parallelHelper_->gridView(), parallelHelper_->dofMapper()); |
303 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
112 | vectorHelper.makeNonOverlappingConsistent(y); |
304 |
2/4✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
✗ Branch 4 not taken.
|
112 | return scalarProduct_->norm(y); |
305 | 112 | } | |
306 | } | ||
307 | #endif | ||
308 | if constexpr (convertMultiTypeVectorAndMatrix) | ||
309 | { | ||
310 | 311 | auto y = VectorConverter<XVector>::multiTypeToBlockVector(x); | |
311 |
2/4✓ Branch 1 taken 311 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 311 times.
✗ Branch 4 not taken.
|
311 | return scalarProduct_->norm(y); |
312 | 311 | } | |
313 | else | ||
314 |
2/3✓ Branch 2 taken 370 times.
✗ Branch 3 not taken.
✓ Branch 1 taken 1 times.
|
8951 | return scalarProduct_->norm(x); |
315 | } | ||
316 | |||
317 | /*! | ||
318 | * \brief The name of the linear solver | ||
319 | */ | ||
320 | 7 | const std::string& name() const | |
321 | { | ||
322 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | return name_; |
323 | } | ||
324 | |||
325 | /*! | ||
326 | * \brief Set the residual reduction tolerance | ||
327 | */ | ||
328 | 276 | void setResidualReduction(double residReduction) | |
329 | { | ||
330 |
2/4✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
|
276 | params_["reduction"] = std::to_string(residReduction); |
331 | |||
332 | // reconstruct the solver with new parameters | ||
333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
|
276 | if (solver_) |
334 | ✗ | solver_ = constructPreconditionedSolver_(linearOperator_); | |
335 | 276 | } | |
336 | |||
337 | /*! | ||
338 | * \brief Set the maximum number of linear solver iterations | ||
339 | */ | ||
340 | void setMaxIter(std::size_t maxIter) | ||
341 | { | ||
342 | params_["maxit"] = std::to_string(maxIter); | ||
343 | |||
344 | // reconstruct the solver with new parameters | ||
345 | if (solver_) | ||
346 | solver_ = constructPreconditionedSolver_(linearOperator_); | ||
347 | } | ||
348 | |||
349 | /*! | ||
350 | * \brief Set the linear solver parameters | ||
351 | * \param params Either a std::string giving a parameter group (parameters are read from input file) or a Dune::ParameterTree | ||
352 | * \note In case of a Dune::ParameterTree, the parameters are passed straight to the linear solver and preconditioner | ||
353 | */ | ||
354 | 19 | void setParams(const ParameterInitializer& params) | |
355 | { | ||
356 | #if HAVE_MPI | ||
357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | if (communication_) |
358 | ✗ | initializeParameters_(params, communication_->communicator()); | |
359 | else | ||
360 | 19 | initializeParameters_(params); | |
361 | #else | ||
362 | initializeParameters_(params); | ||
363 | #endif | ||
364 | |||
365 | // reconstruct the solver with new parameters | ||
366 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (solver_) |
367 | 19 | solver_ = constructPreconditionedSolver_(linearOperator_); | |
368 | 19 | } | |
369 | |||
370 | private: | ||
371 | |||
372 |
2/2✓ Branch 0 taken 381 times.
✓ Branch 1 taken 19 times.
|
456 | void initializeParameters_(const ParameterInitializer& params) |
373 | { | ||
374 |
2/2✓ Branch 0 taken 381 times.
✓ Branch 1 taken 19 times.
|
456 | if (std::holds_alternative<std::string>(params)) |
375 | 425 | params_ = Dumux::LinearSolverParameters<LinearSolverTraits>::createParameterTree(std::get<std::string>(params)); | |
376 | else | ||
377 | 31 | params_ = std::get<Dune::ParameterTree>(params); | |
378 | 456 | } | |
379 | |||
380 | template <class Comm> | ||
381 | 284 | void initializeParameters_(const ParameterInitializer& params, const Comm& comm) | |
382 | { | ||
383 |
5/8✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 247 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
|
284 | initializeParameters_(params); |
384 | |||
385 | // disable verbose output on all ranks except rank 0 | ||
386 |
3/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
260 | if (comm.rank() != 0) |
387 |
1/4✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
11 | Dumux::LinearSolverParameters<LinearSolverTraits>::disableVerbosity(params_); |
388 | 24 | } | |
389 | |||
390 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
29732 | MatrixOperatorHolder makeSequentialLinearOperator_(std::shared_ptr<Matrix> A) |
391 | { | ||
392 | using SequentialTraits = typename LinearSolverTraits::template Sequential<MatrixForSolver, XVectorForSolver>; | ||
393 | if constexpr (convertMultiTypeVectorAndMatrix) | ||
394 | { | ||
395 | // create the BCRS matrix the IterativeSolver backend can handle | ||
396 |
1/2✓ Branch 3 taken 855 times.
✗ Branch 4 not taken.
|
1710 | auto M = std::make_shared<MatrixForSolver>(MatrixConverter<Matrix>::multiTypeToBCRSMatrix(*A)); |
397 |
1/4✓ Branch 0 taken 855 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
855 | return std::make_shared<typename SequentialTraits::LinearOperator>(M); |
398 | 855 | } | |
399 | else | ||
400 | { | ||
401 |
2/4✓ Branch 0 taken 28817 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
28893 | return std::make_shared<typename SequentialTraits::LinearOperator>(A); |
402 | } | ||
403 | } | ||
404 | |||
405 | template<class ParallelTraits> | ||
406 | 5236 | MatrixOperatorHolder makeParallelLinearOperator_(std::shared_ptr<Matrix> A, ParallelTraits = {}) | |
407 | { | ||
408 | #if HAVE_MPI | ||
409 | // make matrix consistent | ||
410 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
654 | prepareMatrixParallel<LinearSolverTraits, ParallelTraits>(*A, *parallelHelper_); |
411 |
2/10✗ Branch 1 not taken.
✓ Branch 2 taken 4582 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 5 taken 4582 times.
✗ Branch 10 not taken.
|
5236 | return std::make_shared<typename ParallelTraits::LinearOperator>(std::move(A), *communication_); |
412 | #else | ||
413 | DUNE_THROW(Dune::InvalidStateException, "Calling makeParallelLinearOperator for sequential run"); | ||
414 | #endif | ||
415 | } | ||
416 | |||
417 | 34 | MatrixOperatorHolder makeParallelOrSequentialLinearOperator_(std::shared_ptr<Matrix> A) | |
418 | { | ||
419 | return executeSequentialOrParallel_( | ||
420 |
2/4✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
|
64 | [&]{ return makeSequentialLinearOperator_(std::move(A)); }, |
421 |
1/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
42 | [&](auto traits){ return makeParallelLinearOperator_(std::move(A), traits); } |
422 |
2/3✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 0 taken 31 times.
|
34 | ); |
423 | } | ||
424 | |||
425 | 30419 | MatrixOperatorHolder makeSequentialLinearOperator_(Matrix& A) | |
426 |
2/4✓ Branch 1 taken 29716 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28861 times.
✗ Branch 4 not taken.
|
60838 | { return makeSequentialLinearOperator_(Dune::stackobject_to_shared_ptr<Matrix>(A)); } |
427 | |||
428 | MatrixOperatorHolder makeParallelOrSequentialLinearOperator_(Matrix& A) | ||
429 | { return makeParallelOrSequentialLinearOperator_(Dune::stackobject_to_shared_ptr<Matrix>(A)); } | ||
430 | |||
431 | template<class ParallelTraits> | ||
432 | 10468 | MatrixOperatorHolder makeParallelLinearOperator_(Matrix& A, ParallelTraits = {}) | |
433 |
2/4✓ Branch 1 taken 5234 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4582 times.
|
11772 | { return makeParallelLinearOperator_<ParallelTraits>(Dune::stackobject_to_shared_ptr<Matrix>(A)); } |
434 | |||
435 | 30419 | IstlSolverResult solveSequential_(Matrix& A, XVector& x, BVector& b) | |
436 | { | ||
437 | // construct solver from linear operator | ||
438 | 30419 | auto linearOperatorHolder = makeSequentialLinearOperator_(A); | |
439 | 30419 | auto solver = constructPreconditionedSolver_(linearOperatorHolder); | |
440 | |||
441 |
1/2✓ Branch 1 taken 855 times.
✗ Branch 2 not taken.
|
89545 | return solveSequential_(x, b, *solver); |
442 | 33443 | } | |
443 | |||
444 |
3/4✓ Branch 1 taken 29664 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
|
29723 | IstlSolverResult solveSequential_(XVector& x, BVector& b, InverseOperator& solver) const |
445 | { | ||
446 | 29785 | Dune::InverseOperatorResult result; | |
447 | if constexpr (convertMultiTypeVectorAndMatrix) | ||
448 | { | ||
449 | // create the vector the IterativeSolver backend can handle | ||
450 |
1/2✓ Branch 1 taken 855 times.
✗ Branch 2 not taken.
|
855 | BVectorForSolver bTmp = VectorConverter<BVector>::multiTypeToBlockVector(b); |
451 | |||
452 | // create a block vector to which the linear solver writes the solution | ||
453 |
1/2✓ Branch 1 taken 855 times.
✗ Branch 2 not taken.
|
855 | XVectorForSolver y(bTmp.size()); |
454 | |||
455 | // solve linear system | ||
456 |
1/2✓ Branch 1 taken 855 times.
✗ Branch 2 not taken.
|
855 | solver.apply(y, bTmp, result); |
457 | |||
458 | // copy back the result y into x | ||
459 |
1/2✓ Branch 0 taken 855 times.
✗ Branch 1 not taken.
|
855 | if (result.converged) |
460 | 855 | VectorConverter<XVector>::retrieveValues(x, y); | |
461 | 855 | } | |
462 | else | ||
463 | { | ||
464 | // solve linear system | ||
465 |
3/4✓ Branch 1 taken 28809 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
|
28930 | solver.apply(x, b, result); |
466 | } | ||
467 | |||
468 |
2/4✓ Branch 0 taken 28809 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
|
29722 | return result; |
469 | } | ||
470 | |||
471 | 34950 | IstlSolverResult solveSequentialOrParallel_(Matrix& A, XVector& x, BVector& b) | |
472 | { | ||
473 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 1 times.
|
35072 | return executeSequentialOrParallel_( |
474 | 93567 | [&]{ return solveSequential_(A, x, b); }, | |
475 |
5/8✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 506 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 1 taken 24 times.
✓ Branch 4 taken 1 times.
|
34950 | [&](auto traits){ return solveParallel_(A, x, b, traits); } |
476 | ); | ||
477 | } | ||
478 | |||
479 | 169 | IstlSolverResult solveSequentialOrParallel_(XVector& x, BVector& b, InverseOperator& solver) const | |
480 | { | ||
481 | 169 | return executeSequentialOrParallel_( | |
482 | 100 | [&]{ return solveSequential_(x, b, solver); }, | |
483 | 157 | [&](auto traits){ return solveParallel_(x, b, solver, traits); } | |
484 | ); | ||
485 | } | ||
486 | |||
487 | template<class ParallelTraits> | ||
488 | 10468 | IstlSolverResult solveParallel_(Matrix& A, XVector& x, BVector& b, ParallelTraits = {}) | |
489 | { | ||
490 | // construct solver from linear operator | ||
491 | 10468 | auto linearOperatorHolder = makeParallelLinearOperator_<ParallelTraits>(A); | |
492 | 10468 | auto solver = constructPreconditionedSolver_(linearOperatorHolder); | |
493 |
1/2✓ Branch 1 taken 652 times.
✗ Branch 2 not taken.
|
28796 | return solveParallel_<ParallelTraits>(x, b, *solver); |
494 | 10468 | } | |
495 | |||
496 | template<class ParallelTraits> | ||
497 | 5334 | IstlSolverResult solveParallel_(XVector& x, BVector& b, InverseOperator& solver, ParallelTraits = {}) const | |
498 | { | ||
499 | #if HAVE_MPI | ||
500 | // make right hand side consistent | ||
501 |
2/5✓ Branch 3 taken 4580 times.
✗ Branch 4 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
|
5334 | prepareVectorParallel<LinearSolverTraits, ParallelTraits>(b, *parallelHelper_); |
502 | |||
503 | // solve linear system | ||
504 | 5334 | Dune::InverseOperatorResult result; | |
505 |
1/5✗ Branch 1 not taken.
✓ Branch 2 taken 4582 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 3 not taken.
|
5334 | solver.apply(x, b, result); |
506 |
1/4✓ Branch 0 taken 4582 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
4582 | return result; |
507 | #else | ||
508 | DUNE_THROW(Dune::InvalidStateException, "Calling makeParallelLinearOperator for sequential run"); | ||
509 | #endif | ||
510 | } | ||
511 | |||
512 | |||
513 | 35003 | std::shared_ptr<InverseOperator> constructPreconditionedSolver_(MatrixOperatorHolder& ops) | |
514 | { | ||
515 |
9/17✓ Branch 1 taken 4582 times.
✓ Branch 2 taken 782 times.
✓ Branch 4 taken 652 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26593 times.
✓ Branch 8 taken 48 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 24 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 16 taken 51 times.
✗ Branch 17 not taken.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 9 taken 12 times.
✓ Branch 0 taken 2256 times.
✗ Branch 12 not taken.
|
98933 | return std::visit([&](auto&& op) |
516 | { | ||
517 | using LinearOperator = typename std::decay_t<decltype(op)>::element_type; | ||
518 |
6/12✓ Branch 2 taken 3692 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 4582 times.
✗ Branch 10 not taken.
✓ Branch 16 taken 26040 times.
✗ Branch 17 not taken.
✓ Branch 23 taken 36 times.
✗ Branch 24 not taken.
✓ Branch 30 taken 500 times.
✗ Branch 31 not taken.
✓ Branch 37 taken 153 times.
✗ Branch 38 not taken.
|
35003 | const auto& params = params_.sub("preconditioner"); |
519 | using Prec = Dune::Preconditioner<typename LinearOperator::domain_type, typename LinearOperator::range_type>; | ||
520 | #if DUNE_VERSION_GTE(DUNE_ISTL,2,11) | ||
521 | using OpTraits = Dune::OperatorTraits<LinearOperator>; | ||
522 | std::shared_ptr<Prec> prec = PreconditionerFactory{}(OpTraits{}, op, params); | ||
523 | #else | ||
524 | using TL = Dune::TypeList<typename LinearOperator::matrix_type, typename LinearOperator::domain_type, typename LinearOperator::range_type>; | ||
525 |
6/12✓ Branch 2 taken 3692 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 4582 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 26040 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 36 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 500 times.
✗ Branch 19 not taken.
✓ Branch 22 taken 153 times.
✗ Branch 23 not taken.
|
35003 | std::shared_ptr<Prec> prec = PreconditionerFactory{}(TL{}, op, params); |
526 | #endif | ||
527 | |||
528 | #if HAVE_MPI | ||
529 | #if DUNE_VERSION_LT(DUNE_ISTL,2,11) | ||
530 |
24/60✓ Branch 1 taken 3692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3692 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3690 times.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 4582 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 4582 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2464 times.
✓ Branch 20 taken 2118 times.
✓ Branch 22 taken 2464 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 2464 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 26040 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 26040 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✓ Branch 33 taken 26040 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✓ Branch 40 taken 36 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 36 times.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✓ Branch 46 taken 36 times.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✓ Branch 53 taken 500 times.
✗ Branch 54 not taken.
✓ Branch 56 taken 500 times.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✓ Branch 59 taken 500 times.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✓ Branch 66 taken 153 times.
✗ Branch 67 not taken.
✓ Branch 69 taken 153 times.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✓ Branch 72 taken 153 times.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
|
35003 | if (prec->category() != op->category() && prec->category() == Dune::SolverCategory::sequential) |
531 |
2/23✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 2464 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 10 not taken.
✗ Branch 0 not taken.
✗ Branch 15 not taken.
|
4932 | prec = Dune::wrapPreconditioner4Parallel(prec, op); |
532 | #else | ||
533 | if constexpr (OpTraits::isParallel) | ||
534 | { | ||
535 | using Comm = typename OpTraits::comm_type; | ||
536 | const Comm& comm = OpTraits::getCommOrThrow(op); | ||
537 | if (op->category() == Dune::SolverCategory::overlapping && prec->category() == Dune::SolverCategory::sequential) | ||
538 | prec = std::make_shared<Dune::BlockPreconditioner<typename OpTraits::domain_type, typename OpTraits::range_type,Comm> >(prec, comm); | ||
539 | else if (op->category() == Dune::SolverCategory::nonoverlapping && prec->category() == Dune::SolverCategory::sequential) | ||
540 | prec = std::make_shared<Dune::NonoverlappingBlockPreconditioner<Comm, Prec> >(prec, comm); | ||
541 | } | ||
542 | #endif | ||
543 | #endif | ||
544 |
12/24✓ Branch 1 taken 3692 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3692 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4582 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4582 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 26040 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 26040 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 36 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 36 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 500 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 500 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 153 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 153 times.
✗ Branch 29 not taken.
|
35003 | return std::make_shared<InverseOperator>(op, scalarProduct_, prec, params_); |
545 |
10/19✓ Branch 1 taken 6831 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 652 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26592 times.
✓ Branch 8 taken 1 times.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 16 taken 51 times.
✗ Branch 17 not taken.
✓ Branch 0 taken 7 times.
✓ Branch 3 taken 782 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 60 times.
✓ Branch 12 taken 24 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
70006 | }, ops); |
546 | } | ||
547 | |||
548 | template<class Seq, class Par> | ||
549 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
35153 | decltype(auto) executeSequentialOrParallel_(Seq&& sequentialAction, Par&& parallelAction) const |
550 | { | ||
551 | #if HAVE_MPI | ||
552 | // For Dune::MultiTypeBlockMatrix there is currently no generic way | ||
553 | // of handling parallelism, we therefore can only solve these types of systems sequentially | ||
554 | if constexpr (isMultiTypeBlockMatrix<Matrix>::value || !LinearSolverTraits::canCommunicate) | ||
555 |
1/2✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
50 | return sequentialAction(); |
556 | else | ||
557 | { | ||
558 |
3/4✓ Branch 0 taken 25956 times.
✓ Branch 1 taken 652 times.
✓ Branch 2 taken 4582 times.
✗ Branch 3 not taken.
|
32079 | switch (solverCategory_) |
559 | { | ||
560 | 26743 | case Dune::SolverCategory::sequential: | |
561 | 26743 | return sequentialAction(); | |
562 | 754 | case Dune::SolverCategory::nonoverlapping: | |
563 | using NOTraits = typename LinearSolverTraits::template ParallelNonoverlapping<Matrix, XVector>; | ||
564 | 754 | return parallelAction(NOTraits{}); | |
565 | 4582 | case Dune::SolverCategory::overlapping: | |
566 | using OTraits = typename LinearSolverTraits::template ParallelOverlapping<Matrix, XVector>; | ||
567 | 4582 | return parallelAction(OTraits{}); | |
568 | ✗ | default: DUNE_THROW(Dune::InvalidStateException, "Unknown solver category"); | |
569 | } | ||
570 | } | ||
571 | #else | ||
572 | return sequentialAction(); | ||
573 | #endif | ||
574 | } | ||
575 | |||
576 | #if HAVE_MPI | ||
577 | std::shared_ptr<const ParallelHelper> parallelHelper_; | ||
578 | std::shared_ptr<Comm> communication_; | ||
579 | #endif | ||
580 | |||
581 | Dune::SolverCategory::Category solverCategory_; | ||
582 | std::shared_ptr<ScalarProduct> scalarProduct_; | ||
583 | |||
584 | // for stored solvers (reuse matrix) | ||
585 | MatrixOperatorHolder linearOperator_; | ||
586 | // for stored solvers (reuse matrix) | ||
587 | std::shared_ptr<InverseOperator> solver_; | ||
588 | |||
589 | Dune::ParameterTree params_; | ||
590 | std::string name_; | ||
591 | }; | ||
592 | |||
593 | } // end namespace Dumux::Detail | ||
594 | |||
595 | namespace Dumux { | ||
596 | |||
597 | /*! | ||
598 | * \ingroup Linear | ||
599 | * \brief An ILU preconditioned BiCGSTAB solver using dune-istl | ||
600 | * | ||
601 | * Solver: The BiCGSTAB (stabilized biconjugate gradients method) solver has | ||
602 | * faster and smoother convergence than the original BiCG. It can be applied to | ||
603 | * nonsymmetric matrices.\n | ||
604 | * See: Van der Vorst, H. A. (1992). "Bi-CGSTAB: A Fast and Smoothly Converging | ||
605 | * Variant of Bi-CG for the Solution of Nonsymmetric Linear Systems". | ||
606 | * SIAM J. Sci. and Stat. Comput. 13 (2): 631–644. doi:10.1137/0913035. | ||
607 | * | ||
608 | * Preconditioner: ILU(n) incomplete LU factorization. The order n indicates | ||
609 | * fill-in. It can be damped by the relaxation parameter | ||
610 | * LinearSolver.PreconditionerRelaxation.\n | ||
611 | * See: Golub, G. H., and Van Loan, C. F. (2012). Matrix computations. JHU Press. | ||
612 | */ | ||
613 | template<class LSTraits, class LATraits> | ||
614 | using ILUBiCGSTABIstlSolver = | ||
615 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
616 | Dune::BiCGSTABSolver<typename LATraits::SingleTypeVector>, | ||
617 | Detail::IstlSolvers::IstlDefaultBlockLevelPreconditionerFactory<Dune::SeqILU>, | ||
618 | // the Dune::ILU preconditioners don't accept multi-type matrices | ||
619 | /*convert multi-type istl types?*/ true | ||
620 | >; | ||
621 | |||
622 | /*! | ||
623 | * \ingroup Linear | ||
624 | * \brief An ILU preconditioned GMres solver using dune-istl | ||
625 | * | ||
626 | * Solver: The GMRes (generalized minimal residual) method is an iterative | ||
627 | * method for the numerical solution of a nonsymmetric system of linear | ||
628 | * equations.\n | ||
629 | * See: Saad, Y., Schultz, M. H. (1986). "GMRES: A generalized minimal residual | ||
630 | * algorithm for solving nonsymmetric linear systems." SIAM J. Sci. and Stat. | ||
631 | * Comput. 7: 856–869. | ||
632 | * | ||
633 | * Preconditioner: ILU(n) incomplete LU factorization. The order n indicates | ||
634 | * fill-in. It can be damped by the relaxation parameter | ||
635 | * LinearSolver.PreconditionerRelaxation.\n | ||
636 | * See: Golub, G. H., and Van Loan, C. F. (2012). Matrix computations. JHU Press. | ||
637 | */ | ||
638 | template<class LSTraits, class LATraits> | ||
639 | using ILURestartedGMResIstlSolver = | ||
640 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
641 | Dune::RestartedGMResSolver<typename LATraits::SingleTypeVector>, | ||
642 | Detail::IstlSolvers::IstlDefaultBlockLevelPreconditionerFactory<Dune::SeqILU>, | ||
643 | // the Dune::ILU preconditioners don't accept multi-type matrices | ||
644 | /*convert multi-type istl types?*/ true | ||
645 | >; | ||
646 | |||
647 | /*! | ||
648 | * \ingroup Linear | ||
649 | * \brief An SSOR-preconditioned BiCGSTAB solver using dune-istl | ||
650 | * | ||
651 | * Solver: The BiCGSTAB (stabilized biconjugate gradients method) solver has | ||
652 | * faster and smoother convergence than the original BiCG. While, it can be | ||
653 | * applied to nonsymmetric matrices, the preconditioner SSOR assumes symmetry.\n | ||
654 | * See: Van der Vorst, H. A. (1992). "Bi-CGSTAB: A Fast and Smoothly Converging | ||
655 | * Variant of Bi-CG for the Solution of Nonsymmetric Linear Systems". | ||
656 | * SIAM J. Sci. and Stat. Comput. 13 (2): 631–644. doi:10.1137/0913035. | ||
657 | * | ||
658 | * Preconditioner: SSOR symmetric successive overrelaxation method. The | ||
659 | * relaxation is controlled by the parameter LinearSolver.PreconditionerRelaxation. | ||
660 | * In each preconditioning step, it is applied as often as given by the parameter | ||
661 | * LinearSolver.PreconditionerIterations.\n | ||
662 | * See: Golub, G. H., and Van Loan, C. F. (2012). Matrix computations. JHU Press. | ||
663 | */ | ||
664 | template<class LSTraits, class LATraits> | ||
665 | using SSORBiCGSTABIstlSolver = | ||
666 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
667 | Dune::BiCGSTABSolver<typename LATraits::Vector>, | ||
668 | Detail::IstlSolvers::IstlDefaultBlockLevelPreconditionerFactory<Dune::SeqSSOR> | ||
669 | >; | ||
670 | |||
671 | /*! | ||
672 | * \ingroup Linear | ||
673 | * \brief An SSOR-preconditioned CG solver using dune-istl | ||
674 | * | ||
675 | * Solver: CG (conjugate gradient) is an iterative method for solving linear | ||
676 | * systems with a symmetric, positive definite matrix.\n | ||
677 | * See: Helfenstein, R., Koko, J. (2010). "Parallel preconditioned conjugate | ||
678 | * gradient algorithm on GPU", Journal of Computational and Applied Mathematics, | ||
679 | * Volume 236, Issue 15, Pages 3584–3590, http://dx.doi.org/10.1016/j.cam.2011.04.025. | ||
680 | * | ||
681 | * Preconditioner: SSOR symmetric successive overrelaxation method. The | ||
682 | * relaxation is controlled by the parameter LinearSolver.PreconditionerRelaxation. | ||
683 | * In each preconditioning step, it is applied as often as given by the parameter | ||
684 | * LinearSolver.PreconditionerIterations.\n | ||
685 | * See: Golub, G. H., and Van Loan, C. F. (2012). Matrix computations. JHU Press. | ||
686 | */ | ||
687 | template<class LSTraits, class LATraits> | ||
688 | using SSORCGIstlSolver = | ||
689 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
690 | Dune::CGSolver<typename LATraits::Vector>, | ||
691 | Detail::IstlSolvers::IstlDefaultBlockLevelPreconditionerFactory<Dune::SeqSSOR> | ||
692 | >; | ||
693 | |||
694 | /*! | ||
695 | * \ingroup Linear | ||
696 | * \brief An AMG preconditioned BiCGSTAB solver using dune-istl | ||
697 | * | ||
698 | * Solver: The BiCGSTAB (stabilized biconjugate gradients method) solver has | ||
699 | * faster and smoother convergence than the original BiCG. While, it can be | ||
700 | * applied to nonsymmetric matrices, the preconditioner SSOR assumes symmetry.\n | ||
701 | * See: Van der Vorst, H. A. (1992). "Bi-CGSTAB: A Fast and Smoothly Converging | ||
702 | * Variant of Bi-CG for the Solution of Nonsymmetric Linear Systems". | ||
703 | * SIAM J. Sci. and Stat. Comput. 13 (2): 631–644. doi:10.1137/0913035. | ||
704 | * | ||
705 | * Preconditioner: AMG (algebraic multigrid) | ||
706 | */ | ||
707 | template<class LSTraits, class LATraits> | ||
708 | using AMGBiCGSTABIstlSolver = | ||
709 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
710 | Dune::BiCGSTABSolver<typename LATraits::SingleTypeVector>, | ||
711 | Detail::IstlSolvers::IstlAmgPreconditionerFactory, | ||
712 | // the AMG preconditioner doesn't accept multi-type matrices | ||
713 | /*convert multi-type istl types?*/ true | ||
714 | >; | ||
715 | |||
716 | /*! | ||
717 | * \ingroup Linear | ||
718 | * \brief An AMG preconditioned CG solver using dune-istl | ||
719 | * | ||
720 | * Solver: CG (conjugate gradient) is an iterative method for solving linear | ||
721 | * systems with a symmetric, positive definite matrix.\n | ||
722 | * See: Helfenstein, R., Koko, J. (2010). "Parallel preconditioned conjugate | ||
723 | * gradient algorithm on GPU", Journal of Computational and Applied Mathematics, | ||
724 | * Volume 236, Issue 15, Pages 3584–3590, http://dx.doi.org/10.1016/j.cam.2011.04.025. | ||
725 | * | ||
726 | * Preconditioner: AMG (algebraic multigrid) | ||
727 | */ | ||
728 | template<class LSTraits, class LATraits> | ||
729 | using AMGCGIstlSolver = | ||
730 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
731 | Dune::CGSolver<typename LATraits::SingleTypeVector>, | ||
732 | Detail::IstlSolvers::IstlAmgPreconditionerFactory, | ||
733 | // the AMG preconditioner doesn't accept multi-type matrices | ||
734 | /*convert multi-type istl types?*/ true | ||
735 | >; | ||
736 | |||
737 | /*! | ||
738 | * \ingroup Linear | ||
739 | * \brief An Uzawa preconditioned BiCGSTAB solver using dune-istl | ||
740 | * | ||
741 | * Solver: The BiCGSTAB (stabilized biconjugate gradients method) solver has | ||
742 | * faster and smoother convergence than the original BiCG. While, it can be | ||
743 | * applied to nonsymmetric matrices, the preconditioner SSOR assumes symmetry.\n | ||
744 | * See: Van der Vorst, H. A. (1992). "Bi-CGSTAB: A Fast and Smoothly Converging | ||
745 | * Variant of Bi-CG for the Solution of Nonsymmetric Linear Systems". | ||
746 | * SIAM J. Sci. and Stat. Comput. 13 (2): 631–644. doi:10.1137/0913035. | ||
747 | * | ||
748 | * Preconditioner: Uzawa method for saddle point problems | ||
749 | * \note Expects a 2x2 MultiTypeBlockMatrix | ||
750 | */ | ||
751 | template<class LSTraits, class LATraits> | ||
752 | using UzawaBiCGSTABIstlSolver = | ||
753 | Detail::IstlIterativeLinearSolver<LSTraits, LATraits, | ||
754 | Dune::BiCGSTABSolver<typename LATraits::Vector>, | ||
755 | Detail::IstlSolvers::IstlDefaultBlockLevelPreconditionerFactory<Dumux::SeqUzawa> | ||
756 | >; | ||
757 | |||
758 | } // end namespace Dumux | ||
759 | |||
760 | namespace Dumux::Detail { | ||
761 | |||
762 | /*! | ||
763 | * \ingroup Linear | ||
764 | * \brief Direct dune-istl linear solvers | ||
765 | */ | ||
766 | template<class LSTraits, class LATraits, template<class M> class Solver, | ||
767 | bool convertMultiTypeVectorAndMatrix = isMultiTypeBlockVector<typename LATraits::Vector>::value> | ||
768 | class DirectIstlSolver : public LinearSolver | ||
769 | { | ||
770 | using Matrix = typename LATraits::Matrix; | ||
771 | using XVector = typename LATraits::Vector; | ||
772 | using BVector = typename LATraits::Vector; | ||
773 | |||
774 | using MatrixForSolver = typename Detail::IstlSolvers::MatrixForSolver<Matrix, convertMultiTypeVectorAndMatrix>::type; | ||
775 | using BVectorForSolver = typename Detail::IstlSolvers::VectorForSolver<BVector, convertMultiTypeVectorAndMatrix>::type; | ||
776 | using XVectorForSolver = typename Detail::IstlSolvers::VectorForSolver<XVector, convertMultiTypeVectorAndMatrix>::type; | ||
777 | using InverseOperator = Dune::InverseOperator<XVectorForSolver, BVectorForSolver>; | ||
778 | public: | ||
779 | using LinearSolver::LinearSolver; | ||
780 | |||
781 | /*! | ||
782 | * \brief Solve the linear system Ax = b | ||
783 | */ | ||
784 | 26838 | IstlSolverResult solve(const Matrix& A, XVector& x, const BVector& b) | |
785 | { | ||
786 | 26838 | return solve_(A, x, b); | |
787 | } | ||
788 | |||
789 | /*! | ||
790 | * \brief Solve the linear system Ax = b using the matrix set with \ref setMatrix | ||
791 | */ | ||
792 | 800 | IstlSolverResult solve(XVector& x, const BVector& b) | |
793 | { | ||
794 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 800 times.
|
800 | if (!solver_) |
795 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Called solve(x, b) but no linear operator has been set"); | |
796 | |||
797 | 800 | return solve_(x, b, *solver_); | |
798 | } | ||
799 | |||
800 | /*! | ||
801 | * \brief Set the matrix A of the linear system Ax = b for reuse | ||
802 | */ | ||
803 | 8 | void setMatrix(std::shared_ptr<Matrix> A) | |
804 | { | ||
805 | if constexpr (convertMultiTypeVectorAndMatrix) | ||
806 | matrix_ = std::make_shared<MatrixForSolver>(MatrixConverter<Matrix>::multiTypeToBCRSMatrix(A)); | ||
807 | else | ||
808 | 8 | matrix_ = A; | |
809 | |||
810 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | solver_ = std::make_shared<Solver<MatrixForSolver>>(*matrix_); |
811 | 8 | } | |
812 | |||
813 | /*! | ||
814 | * \brief Set the matrix A of the linear system Ax = b for reuse | ||
815 | * \note The client has to take care of the lifetime management of A | ||
816 | */ | ||
817 | 8 | void setMatrix(Matrix& A) | |
818 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | { setMatrix(Dune::stackobject_to_shared_ptr(A)); } |
819 | |||
820 | /*! | ||
821 | * \brief name of the linear solver | ||
822 | */ | ||
823 | std::string name() const | ||
824 | { | ||
825 | return "Direct solver"; | ||
826 | } | ||
827 | |||
828 | private: | ||
829 | 26909 | IstlSolverResult solve_(const Matrix& A, XVector& x, const BVector& b) | |
830 | { | ||
831 | // support dune-istl multi-type block vector/matrix by copying | ||
832 | if constexpr (convertMultiTypeVectorAndMatrix) | ||
833 | { | ||
834 | const auto AA = MatrixConverter<Matrix>::multiTypeToBCRSMatrix(A); | ||
835 | Solver<MatrixForSolver> solver(AA, this->verbosity() > 0); | ||
836 | return solve_(x, b, solver); | ||
837 | } | ||
838 | else | ||
839 | { | ||
840 | 26909 | Solver<MatrixForSolver> solver(A, this->verbosity() > 0); | |
841 |
1/2✓ Branch 1 taken 26838 times.
✗ Branch 2 not taken.
|
53818 | return solve_(x, b, solver); |
842 | 26909 | } | |
843 | } | ||
844 | |||
845 |
1/2✓ Branch 1 taken 27638 times.
✗ Branch 2 not taken.
|
27709 | IstlSolverResult solve_(XVector& x, const BVector& b, InverseOperator& solver) const |
846 | { | ||
847 |
1/2✓ Branch 1 taken 5343 times.
✗ Branch 2 not taken.
|
27709 | Dune::InverseOperatorResult result; |
848 | |||
849 | if constexpr (convertMultiTypeVectorAndMatrix) | ||
850 | { | ||
851 | auto bb = VectorConverter<BVector>::multiTypeToBlockVector(b); | ||
852 | XVectorForSolver xx(bb.size()); | ||
853 | solver.apply(xx, bb, result); | ||
854 | checkResult_(xx, result); | ||
855 | if (result.converged) | ||
856 | VectorConverter<XVector>::retrieveValues(x, xx); | ||
857 | return result; | ||
858 | } | ||
859 | else | ||
860 | { | ||
861 |
1/2✓ Branch 1 taken 22295 times.
✗ Branch 2 not taken.
|
27709 | BVectorForSolver bTmp(b); |
862 |
1/2✓ Branch 1 taken 27638 times.
✗ Branch 2 not taken.
|
27709 | solver.apply(x, bTmp, result); |
863 | 27709 | checkResult_(x, result); | |
864 | 55418 | return result; | |
865 | 27709 | } | |
866 | } | ||
867 | |||
868 | |||
869 | 27638 | void checkResult_(XVectorForSolver& x, Dune::InverseOperatorResult& result) const | |
870 | { | ||
871 |
2/4✓ Branch 1 taken 21958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
|
27638 | flatVectorForEach(x, [&](auto&& entry, std::size_t){ |
872 | using std::isnan, std::isinf; | ||
873 |
18/24✓ Branch 0 taken 19338035 times.
✓ Branch 1 taken 1765 times.
✓ Branch 2 taken 151 times.
✓ Branch 3 taken 19337884 times.
✓ Branch 4 taken 5072981 times.
✓ Branch 5 taken 1028 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5072981 times.
✓ Branch 8 taken 2668070 times.
✓ Branch 9 taken 872 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2668070 times.
✓ Branch 12 taken 1566229 times.
✓ Branch 13 taken 1127 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1566229 times.
✓ Branch 16 taken 676210 times.
✓ Branch 17 taken 1392 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 676210 times.
✓ Branch 20 taken 189160 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 189160 times.
|
23084216 | if (isnan(entry) || isinf(entry)) |
874 | 6335 | result.converged = false; | |
875 | }); | ||
876 | } | ||
877 | |||
878 | //! matrix when using the setMatrix interface for matrix reuse | ||
879 | std::shared_ptr<MatrixForSolver> matrix_; | ||
880 | //! solver when using the setMatrix interface for matrix reuse | ||
881 | std::shared_ptr<InverseOperator> solver_; | ||
882 | }; | ||
883 | |||
884 | } // end namespace Dumux::Detail | ||
885 | |||
886 | #if HAVE_SUPERLU | ||
887 | #include <dune/istl/superlu.hh> | ||
888 | |||
889 | namespace Dumux { | ||
890 | |||
891 | /*! | ||
892 | * \ingroup Linear | ||
893 | * \brief Direct linear solver using the SuperLU library. | ||
894 | * | ||
895 | * See: Li, X. S. (2005). "An overview of SuperLU: Algorithms, implementation, | ||
896 | * and user interface." ACM Transactions on Mathematical Software (TOMS) 31(3): 302-325. | ||
897 | * http://crd-legacy.lbl.gov/~xiaoye/SuperLU/ | ||
898 | */ | ||
899 | template<class LSTraits, class LATraits> | ||
900 | using SuperLUIstlSolver = Detail::DirectIstlSolver<LSTraits, LATraits, Dune::SuperLU>; | ||
901 | |||
902 | } // end namespace Dumux | ||
903 | |||
904 | #endif // HAVE_SUPERLU | ||
905 | |||
906 | #if HAVE_UMFPACK | ||
907 | #include <dune/istl/umfpack.hh> | ||
908 | |||
909 | namespace Dumux { | ||
910 | |||
911 | /*! | ||
912 | * \ingroup Linear | ||
913 | * \brief Direct linear solver using the UMFPack library. | ||
914 | * | ||
915 | * See: Davis, Timothy A. (2004). "Algorithm 832". ACM Transactions on | ||
916 | * Mathematical Software 30 (2): 196–199. doi:10.1145/992200.992206. | ||
917 | * http://faculty.cse.tamu.edu/davis/suitesparse.html | ||
918 | */ | ||
919 | template<class LSTraits, class LATraits> | ||
920 | using UMFPackIstlSolver = Detail::DirectIstlSolver<LSTraits, LATraits, Dune::UMFPack, false>; | ||
921 | |||
922 | } // end namespace Dumux | ||
923 | |||
924 | #endif // HAVE_UMFPACK | ||
925 | |||
926 | #endif | ||
927 |