version 3.7
istlsolverfactorybackend.hh
Go to the documentation of this file.
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//
14#ifndef DUMUX_LINEAR_ISTL_SOLVERFACTORYBACKEND_HH
15#define DUMUX_LINEAR_ISTL_SOLVERFACTORYBACKEND_HH
16
17#include <memory>
18
19#include <dune/common/parallel/mpihelper.hh>
20#include <dune/common/parametertree.hh>
21
23
24// preconditioners
25#include <dune/istl/preconditioners.hh>
26#include <dune/istl/paamg/amg.hh>
27#include "preconditioners.hh"
28
29// solvers
30#include <dune/istl/solvers.hh>
31#include <dune/istl/solverfactory.hh>
32
39
40namespace Dumux {
41
42// initSolverFactoriesForMultiTypeBlockMatrix differs in different compilation units,
43// so we have it in an anonymous namespace
44namespace {
45
54template<class LinearOperator>
55int initSolverFactoriesForMultiTypeBlockMatrix()
56{
57 using M = typename LinearOperator::matrix_type;
58 using X = typename LinearOperator::range_type;
59 using Y = typename LinearOperator::domain_type;
60 using TL = Dune::TypeList<M,X,Y>;
61 auto& dsfac = Dune::DirectSolverFactory<M,X,Y>::instance();
62 Dune::addRegistryToFactory<TL>(dsfac, Dumux::MultiTypeBlockMatrixDirectSolverTag{});
63 auto& pfac = Dune::PreconditionerFactory<LinearOperator,X,Y>::instance();
64 Dune::addRegistryToFactory<TL>(pfac, Dumux::MultiTypeBlockMatrixPreconditionerTag{});
65 using TLS = Dune::TypeList<X,Y>;
66 auto& isfac = Dune::IterativeSolverFactory<X,Y>::instance();
67 return Dune::addRegistryToFactory<TLS>(isfac, Dune::IterativeSolverTag{});
68}
69} // end namespace
70
78template<class Matrix, class LinearOperator>
80{
82 initSolverFactoriesForMultiTypeBlockMatrix<LinearOperator>();
83 else
84 Dune::initSolverFactories<LinearOperator>();
85}
86
93namespace Detail {
94
95template <class LinearSolverTraits>
97{
98public:
99
105 [[deprecated("Use new IstlSolverFactoryBackend<LinearSolverTraits, LinearAlgebraTraits> with 2nd template parameter. Will be removed after 3.7.")]]
107 : paramGroup_(paramGroup)
108 , isParallel_(Dune::MPIHelper::getCommunication().size() > 1)
109 {
110 if (isParallel_)
111 DUNE_THROW(Dune::InvalidStateException, "Using sequential constructor for parallel run. Use signature with gridView and dofMapper!");
112
113 firstCall_ = true;
114 initializeParameters_();
115 }
116
124 [[deprecated("Use new IstlSolverFactoryBackend<LinearSolverTraits, LinearAlgebraTraits> with 2nd template parameter. Will be removed after 3.7.")]]
125 OldIstlSolverFactoryBackend(const typename LinearSolverTraits::GridView& gridView,
126 const typename LinearSolverTraits::DofMapper& dofMapper,
127 const std::string& paramGroup = "")
128 : paramGroup_(paramGroup)
129#if HAVE_MPI
130 , isParallel_(Dune::MPIHelper::getCommunication().size() > 1)
131#endif
132 {
133 firstCall_ = true;
134 initializeParameters_();
135#if HAVE_MPI
136 if (isParallel_)
137 parallelHelper_ = std::make_unique<ParallelISTLHelper<LinearSolverTraits>>(gridView, dofMapper);
138#endif
139 }
140
147 void updateAfterGridAdaption(const typename LinearSolverTraits::GridView& gridView,
148 const typename LinearSolverTraits::DofMapper& dofMapper)
149 {
150#if HAVE_MPI
151 if (isParallel_)
152 parallelHelper_ = std::make_unique<ParallelISTLHelper<LinearSolverTraits>>(gridView, dofMapper);
153#endif
154 }
155
163 template<class Matrix, class Vector>
164 bool solve(Matrix& A, Vector& x, Vector& b)
165 {
166#if HAVE_MPI
167 solveSequentialOrParallel_(A, x, b);
168#else
169 solveSequential_(A, x, b);
170#endif
171 firstCall_ = false;
172 return result_.converged;
173 }
174
175 const Dune::InverseOperatorResult& result() const
176 {
177 return result_;
178 }
179
180 const std::string& name() const
181 {
182 return name_;
183 }
184
185private:
186
187 void initializeParameters_()
188 {
190 checkMandatoryParameters_();
191 name_ = params_.get<std::string>("preconditioner.type") + "-preconditioned " + params_.get<std::string>("type");
192 if (params_.get<int>("verbose", 0) > 0)
193 std::cout << "Initialized linear solver of type: " << name_ << std::endl;
194 }
195
196 void checkMandatoryParameters_()
197 {
198 if (!params_.hasKey("type"))
199 DUNE_THROW(Dune::InvalidStateException, "Solver factory needs \"LinearSolver.Type\" parameter to select the solver");
200
201 if (!params_.hasKey("preconditioner.type"))
202 DUNE_THROW(Dune::InvalidStateException, "Solver factory needs \"LinearSolver.Preconditioner.Type\" parameter to select the preconditioner");
203 }
204
205#if HAVE_MPI
206 template<class Matrix, class Vector>
207 void solveSequentialOrParallel_(Matrix& A, Vector& x, Vector& b)
208 {
209 // Dune::MultiTypeBlockMatrix does not provide a ColIterator which is needed by Dune::NonoverlappingSchwarzOperator.
210 // We therefore can only solve these types of systems sequentially.
211 // TODO: This can be adapted once the situation in Dune ISTL changes.
212 if constexpr (LinearSolverTraits::canCommunicate && !isMultiTypeBlockMatrix<Matrix>::value)
213 {
214 if (isParallel_)
215 {
216 if (LinearSolverTraits::isNonOverlapping(parallelHelper_->gridView()))
217 {
218 using PTraits = typename LinearSolverTraits::template ParallelNonoverlapping<Matrix, Vector>;
219 solveParallel_<PTraits>(A, x, b);
220 }
221 else
222 {
223 using PTraits = typename LinearSolverTraits::template ParallelOverlapping<Matrix, Vector>;
224 solveParallel_<PTraits>(A, x, b);
225 }
226 }
227 else
228 solveSequential_(A, x, b);
229 }
230 else
231 {
232 solveSequential_(A, x, b);
233 }
234 }
235
236 template<class ParallelTraits, class Matrix, class Vector>
237 void solveParallel_(Matrix& A, Vector& x, Vector& b)
238 {
239 using Comm = typename ParallelTraits::Comm;
240 using LinearOperator = typename ParallelTraits::LinearOperator;
241 using ScalarProduct = typename ParallelTraits::ScalarProduct;
242
243 if (firstCall_)
244 initSolverFactories<Matrix, LinearOperator>();
245
246 std::shared_ptr<Comm> comm;
247 std::shared_ptr<LinearOperator> linearOperator;
248 std::shared_ptr<ScalarProduct> scalarProduct;
249 prepareLinearAlgebraParallel<LinearSolverTraits, ParallelTraits>(A, b, comm, linearOperator, scalarProduct, *parallelHelper_);
250
251 // construct solver
252 auto solver = getSolverFromFactory_(linearOperator);
253
254 // solve linear system
255 solver->apply(x, b, result_);
256 }
257#endif // HAVE_MPI
258
259 template<class Matrix, class Vector>
260 void solveSequential_(Matrix& A, Vector& x, Vector& b)
261 {
262 // construct linear operator
263 using Traits = typename LinearSolverTraits::template Sequential<Matrix, Vector>;
264 using LinearOperator = typename Traits::LinearOperator;
265 auto linearOperator = std::make_shared<LinearOperator>(A);
266
267 if (firstCall_)
268 initSolverFactories<Matrix, LinearOperator>();
269
270 // construct solver
271 auto solver = getSolverFromFactory_(linearOperator);
272
273 // solve linear system
274 solver->apply(x, b, result_);
275 }
276
277 template<class LinearOperator>
278 auto getSolverFromFactory_(std::shared_ptr<LinearOperator>& fop)
279 {
280 try { return Dune::getSolverFromFactory(fop, params_); }
281 catch(Dune::Exception& e)
282 {
283 std::cerr << "Could not create solver with factory" << std::endl;
284 std::cerr << e.what() << std::endl;
285 throw e;
286 }
287 }
288
289 const std::string paramGroup_;
290#if HAVE_MPI
291 std::unique_ptr<ParallelISTLHelper<LinearSolverTraits>> parallelHelper_;
292#endif
293 bool isParallel_ = false;
294 bool firstCall_;
295
296 Dune::InverseOperatorResult result_;
297 Dune::ParameterTree params_;
298 std::string name_;
299};
300
301template <class LinearSolverTraits, class LinearAlgebraTraits>
303{
304 using Matrix = typename LinearAlgebraTraits::Matrix;
305 using Vector = typename LinearAlgebraTraits::Vector;
306 using ScalarProduct = Dune::ScalarProduct<Vector>;
307#if HAVE_MPI
308 using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>;
309#endif
310public:
311
317 IstlSolverFactoryBackend(const std::string& paramGroup = "")
318 : paramGroup_(paramGroup)
319 , isParallel_(Dune::MPIHelper::getCommunication().size() > 1)
320 {
321 if (isParallel_)
322 DUNE_THROW(Dune::InvalidStateException, "Using sequential constructor for parallel run. Use signature with gridView and dofMapper!");
323
324 firstCall_ = true;
325 initializeParameters_();
326 scalarProduct_ = std::make_shared<ScalarProduct>();
327 solverCategory_ = Dune::SolverCategory::sequential;
328 }
329
337 IstlSolverFactoryBackend(const typename LinearSolverTraits::GridView& gridView,
338 const typename LinearSolverTraits::DofMapper& dofMapper,
339 const std::string& paramGroup = "")
340 : paramGroup_(paramGroup)
341#if HAVE_MPI
342 , isParallel_(gridView.comm().size() > 1)
343#endif
344 {
345 firstCall_ = true;
346 initializeParameters_();
347#if HAVE_MPI
348 solverCategory_ = Detail::solverCategory<LinearSolverTraits>(gridView);
349 if (solverCategory_ != Dune::SolverCategory::sequential)
350 {
351 parallelHelper_ = std::make_unique<ParallelISTLHelper<LinearSolverTraits>>(gridView, dofMapper);
352 comm_ = std::make_shared<Comm>(gridView.comm(), solverCategory_);
353 scalarProduct_ = Dune::createScalarProduct<Vector>(*comm_, solverCategory_);
354 parallelHelper_->createParallelIndexSet(*comm_);
355 }
356 else
357 scalarProduct_ = std::make_shared<ScalarProduct>();
358#else
359 solverCategory_ = Dune::SolverCategory::sequential;
360 scalarProduct_ = std::make_shared<ScalarProduct>();
361#endif
362 }
363
371 bool solve(Matrix& A, Vector& x, Vector& b)
372 {
373#if HAVE_MPI
374 solveSequentialOrParallel_(A, x, b);
375#else
376 solveSequential_(A, x, b);
377#endif
378 firstCall_ = false;
379 return result_.converged;
380 }
381
382 const Dune::InverseOperatorResult& result() const
383 {
384 return result_;
385 }
386
387 const std::string& name() const
388 {
389 return name_;
390 }
391
392 Scalar norm(const Vector& x) const
393 {
394#if HAVE_MPI
396 {
397 if (solverCategory_ == Dune::SolverCategory::nonoverlapping)
398 {
399 auto y(x); // make a copy because the vector needs to be made consistent
400 using GV = typename LinearSolverTraits::GridView;
401 using DM = typename LinearSolverTraits::DofMapper;
402 ParallelVectorHelper<GV, DM, LinearSolverTraits::dofCodim> vectorHelper(parallelHelper_->gridView(), parallelHelper_->dofMapper());
403 vectorHelper.makeNonOverlappingConsistent(y);
404 return scalarProduct_->norm(y);
405 }
406 }
407#endif
408 return scalarProduct_->norm(x);
409 }
410
411private:
412
413 void initializeParameters_()
414 {
416 checkMandatoryParameters_();
417 name_ = params_.get<std::string>("preconditioner.type") + "-preconditioned " + params_.get<std::string>("type");
418 if (params_.get<int>("verbose", 0) > 0)
419 std::cout << "Initialized linear solver of type: " << name_ << std::endl;
420 }
421
422 void checkMandatoryParameters_()
423 {
424 if (!params_.hasKey("type"))
425 DUNE_THROW(Dune::InvalidStateException, "Solver factory needs \"LinearSolver.Type\" parameter to select the solver");
426
427 if (!params_.hasKey("preconditioner.type"))
428 DUNE_THROW(Dune::InvalidStateException, "Solver factory needs \"LinearSolver.Preconditioner.Type\" parameter to select the preconditioner");
429 }
430
431#if HAVE_MPI
432 void solveSequentialOrParallel_(Matrix& A, Vector& x, Vector& b)
433 {
434 // Dune::MultiTypeBlockMatrix does not provide a ColIterator which is needed by Dune::NonoverlappingSchwarzOperator.
435 // We therefore can only solve these types of systems sequentially.
436 // TODO: This can be adapted once the situation in Dune ISTL changes.
437 if constexpr (LinearSolverTraits::canCommunicate && !isMultiTypeBlockMatrix<Matrix>::value)
438 {
439 if (isParallel_)
440 {
441 if (LinearSolverTraits::isNonOverlapping(parallelHelper_->gridView()))
442 {
443 using PTraits = typename LinearSolverTraits::template ParallelNonoverlapping<Matrix, Vector>;
444 solveParallel_<PTraits>(A, x, b);
445 }
446 else
447 {
448 using PTraits = typename LinearSolverTraits::template ParallelOverlapping<Matrix, Vector>;
449 solveParallel_<PTraits>(A, x, b);
450 }
451 }
452 else
453 solveSequential_(A, x, b);
454 }
455 else
456 {
457 solveSequential_(A, x, b);
458 }
459 }
460
461 template<class ParallelTraits>
462 void solveParallel_(Matrix& A, Vector& x, Vector& b)
463 {
464 using LinearOperator = typename ParallelTraits::LinearOperator;
465
466 if (firstCall_)
467 initSolverFactories<Matrix, LinearOperator>();
468
469 prepareLinearAlgebraParallel<LinearSolverTraits, ParallelTraits>(A, b, *parallelHelper_);
470 auto linearOperator = std::make_shared<LinearOperator>(A, *comm_);
471
472 // construct solver
473 auto solver = getSolverFromFactory_(linearOperator);
474
475 // solve linear system
476 solver->apply(x, b, result_);
477 }
478#endif // HAVE_MPI
479
480 void solveSequential_(Matrix& A, Vector& x, Vector& b)
481 {
482 // construct linear operator
483 using Traits = typename LinearSolverTraits::template Sequential<Matrix, Vector>;
484 using LinearOperator = typename Traits::LinearOperator;
485 auto linearOperator = std::make_shared<LinearOperator>(A);
486
487 if (firstCall_)
488 initSolverFactories<Matrix, LinearOperator>();
489
490 // construct solver
491 auto solver = getSolverFromFactory_(linearOperator);
492
493 // solve linear system
494 solver->apply(x, b, result_);
495 }
496
497 template<class LinearOperator>
498 auto getSolverFromFactory_(std::shared_ptr<LinearOperator>& fop)
499 {
500 try { return Dune::getSolverFromFactory(fop, params_); }
501 catch(Dune::Exception& e)
502 {
503 std::cerr << "Could not create solver with factory" << std::endl;
504 std::cerr << e.what() << std::endl;
505 throw e;
506 }
507 }
508
509 const std::string paramGroup_;
510#if HAVE_MPI
511 std::unique_ptr<ParallelISTLHelper<LinearSolverTraits>> parallelHelper_;
512 std::shared_ptr<Comm> comm_;
513#endif
514 bool isParallel_ = false;
515 bool firstCall_;
516
517 std::shared_ptr<ScalarProduct> scalarProduct_;
518 Dune::SolverCategory::Category solverCategory_;
519 Dune::InverseOperatorResult result_;
520 Dune::ParameterTree params_;
521 std::string name_;
522};
523
524template<int i>
526{
527 template<class ...T>
529};
530
531template<>
533{
534 template<class T>
536};
537
538} // end namespace Detail
539
547template<class ...T>
548using IstlSolverFactoryBackend = typename Detail::IstlSolverFactoryBackendImplHelper<sizeof...(T)>::template type<T...>;
549
550} // end namespace Dumux
551
552#endif
Definition: istlsolverfactorybackend.hh:303
IstlSolverFactoryBackend(const typename LinearSolverTraits::GridView &gridView, const typename LinearSolverTraits::DofMapper &dofMapper, const std::string &paramGroup="")
Construct the backend for parallel or sequential runs.
Definition: istlsolverfactorybackend.hh:337
const std::string & name() const
Definition: istlsolverfactorybackend.hh:387
bool solve(Matrix &A, Vector &x, Vector &b)
Solve a linear system.
Definition: istlsolverfactorybackend.hh:371
const Dune::InverseOperatorResult & result() const
Definition: istlsolverfactorybackend.hh:382
IstlSolverFactoryBackend(const std::string &paramGroup="")
Construct the backend for the sequential case only.
Definition: istlsolverfactorybackend.hh:317
Scalar norm(const Vector &x) const
Definition: istlsolverfactorybackend.hh:392
Definition: istlsolverfactorybackend.hh:97
const std::string & name() const
Definition: istlsolverfactorybackend.hh:180
const Dune::InverseOperatorResult & result() const
Definition: istlsolverfactorybackend.hh:175
OldIstlSolverFactoryBackend(const std::string &paramGroup="")
Construct the backend for the sequential case only.
Definition: istlsolverfactorybackend.hh:106
OldIstlSolverFactoryBackend(const typename LinearSolverTraits::GridView &gridView, const typename LinearSolverTraits::DofMapper &dofMapper, const std::string &paramGroup="")
Construct the backend for parallel or sequential runs.
Definition: istlsolverfactorybackend.hh:125
bool solve(Matrix &A, Vector &x, Vector &b)
Solve a linear system.
Definition: istlsolverfactorybackend.hh:164
void updateAfterGridAdaption(const typename LinearSolverTraits::GridView &gridView, const typename LinearSolverTraits::DofMapper &dofMapper)
Update the solver after grid adaption.
Definition: istlsolverfactorybackend.hh:147
Base class for linear solvers.
Definition: solver.hh:27
const std::string & paramGroup() const
the parameter group for getting parameter from the parameter tree
Definition: solver.hh:78
double Scalar
Definition: solver.hh:31
static Dune::ParameterTree createParameterTree(const std::string &paramGroup="")
Create a tree containing parameters required for the linear solvers and precondioners of the Dune IST...
Definition: linearsolverparameters.hh:47
Definition: parallelhelpers.hh:476
void makeNonOverlappingConsistent(Dune::BlockVector< Block, Alloc > &v) const
Make a vector consistent for non-overlapping domain decomposition methods.
Definition: parallelhelpers.hh:484
typename Detail::IstlSolverFactoryBackendImplHelper< sizeof...(T)>::template type< T... > IstlSolverFactoryBackend
A linear solver using the dune-istl solver factory to choose the solver and preconditioner at runtime...
Definition: istlsolverfactorybackend.hh:548
The specialized Dumux macro and tag for the ISTL registry to choose the solver and preconditioner at ...
Generates a parameter tree required for the linear solvers and precondioners of the Dune ISTL.
Type traits to be used with matrix types.
static constexpr bool canCommunicate
Definition: gridcapabilities.hh:51
Definition: adapt.hh:17
void initSolverFactories()
Initialize the solver factories for regular matrices or MultiTypeBlockMatrices.
Definition: istlsolverfactorybackend.hh:79
Definition: common/pdesolver.hh:24
Provides a helper class for nonoverlapping decomposition.
Dumux preconditioners for iterative solvers.
Base class for linear solvers.
Definition: istlsolverfactorybackend.hh:526
V Vector
Definition: linearalgebratraits.hh:53
M Matrix
Definition: linearalgebratraits.hh:52
Helper type to determine whether a given type is a Dune::MultiTypeBlockMatrix.
Definition: matrix.hh:37
Helper type to determine whether a given type is a Dune::MultiTypeBlockVector.
Definition: vector.hh:22
Type traits to be used with vector types.