12#ifndef DUMUX_LINEAR_STOKES_SOLVER_HH
13#define DUMUX_LINEAR_STOKES_SOLVER_HH
19#include <dune/common/parametertree.hh>
20#include <dune/common/hybridutilities.hh>
21#include <dune/common/exceptions.hh>
23#include <dune/istl/matrixindexset.hh>
24#include <dune/istl/preconditioner.hh>
25#include <dune/istl/preconditioners.hh>
26#include <dune/istl/solvers.hh>
27#include <dune/istl/paamg/amg.hh>
60template<
class M,
class X,
class Y,
int l = 2>
64 static_assert(l == 2,
"StokesPreconditioner expects a block level of 2 for Matrix type M.");
66 using A = std::decay_t<decltype(std::declval<M>()[Dune::Indices::_0][Dune::Indices::_0])>;
67 using U = std::decay_t<decltype(std::declval<X>()[Dune::Indices::_0])>;
69 using P = std::decay_t<decltype(std::declval<M>()[Dune::Indices::_1][Dune::Indices::_1])>;
70 using V = std::decay_t<decltype(std::declval<X>()[Dune::Indices::_1])>;
72 enum class Mode { symmetric, triangular, diagonal };
95 const std::shared_ptr<
const Dune::AssembledLinearOperator<M,X,Y>>& fullLinearOperator,
96 const std::shared_ptr<const PressureLinearOperator>& pressureLinearOperator,
97 const Dune::ParameterTree& params
99 : matrix_(fullLinearOperator->getmat())
100 , pmatrix_(pressureLinearOperator->getmat())
101 , verbosity_(params.get<int>(
"verbosity"))
102 , paramGroup_(params.get<std::string>(
"ParameterGroup"))
104 const auto mode = getParamFromGroup<std::string>(
105 paramGroup_,
"LinearSolver.Preconditioner.Mode",
"Diagonal"
108 if (mode ==
"Symmetric")
109 mode_ = Mode::symmetric;
110 else if (mode ==
"Triangular")
111 mode_ = Mode::triangular;
113 mode_ = Mode::diagonal;
115 initPreconditioner_(params);
121 void pre(X& update, Y& currentDefect)
override {}
134 void apply(X& update,
const Y& currentDefect)
override
136 using namespace Dune::Indices;
138 if (mode_ == Mode::symmetric)
140 update = applyRightBlock_(currentDefect);
141 update = applyDiagBlock_(update);
142 update = applyLeftBlock_(update);
144 else if (mode_ == Mode::triangular)
146 update = applyRightBlock_(currentDefect);
147 update = applyDiagBlock_(update);
150 update = applyDiagBlock_(currentDefect);
156 void post(X& update)
override {}
159 Dune::SolverCategory::Category
category()
const override
161 return Dune::SolverCategory::sequential;
165 X applyRightBlock_(
const Y& d)
167 using namespace Dune::Indices;
177 auto vTmp = d; vTmp = 0.0;
180 applyPreconditionerForA_(vTmp[_0], dTmp0);
183 matrix_[_1][_0].mv(vTmp[_0], vTmp[_1]);
192 X applyDiagBlock_(
const Y& d)
194 using namespace Dune::Indices;
201 if (mode_ == Mode::diagonal)
202 applyPreconditionerForA_(v[_0], dTmp[_0]);
209 applyPreconditionerForP_(v[_1], dTmp[_1]);
214 X applyLeftBlock_(
const Y& d)
216 using namespace Dune::Indices;
226 auto vTmp = d; vTmp = 0.0;
229 matrix_[_0][_1].umv(dTmp[_1], vTmp[_0]);
232 auto vTmp0 = vTmp[_0]; vTmp0 = 0.0;
233 applyPreconditionerForA_(vTmp0, vTmp[_0]);
242 void initPreconditioner_(
const Dune::ParameterTree& params)
244 using namespace Dune::Indices;
246 if (getParamFromGroup<bool>(paramGroup_,
"LinearSolver.DirectSolverForVelocity",
false))
249 directSolverForA_ = std::make_shared<Dune::UMFPack<A>>(matrix_[_0][_0], verbosity_);
250 using Wrap = Dune::InverseOperator2Preconditioner<Dune::InverseOperator<U, U>>;
251 preconditionerForA_ = std::make_shared<Wrap>(*directSolverForA_);
253 DUNE_THROW(Dune::InvalidStateException,
"Selected direct solver but UMFPack is not available.");
258 using VelLinearOperator = Dune::MatrixAdapter<A, U, U>;
259 auto lopV = std::make_shared<VelLinearOperator>(matrix_[_0][_0]);
260 preconditionerForA_ = std::make_shared<
261 Dune::Amg::AMG<VelLinearOperator, U, Dumux::ParMTSSOR<A,U,U>>
265 if (getParamFromGroup<bool>(paramGroup_,
"LinearSolver.DirectSolverForPressure",
false))
268 directSolverForP_ = std::make_shared<Dune::UMFPack<P>>(pmatrix_, verbosity_);
269 using Wrap = Dune::InverseOperator2Preconditioner<Dune::InverseOperator<V, V>>;
270 preconditionerForP_ = std::make_shared<Wrap>(*directSolverForP_);
272 DUNE_THROW(Dune::InvalidStateException,
"Selected direct solver but UMFPack is not available.");
278 std::size_t numIterations = pmatrix_.nonzeroes() == pmatrix_.N() ? 1 : 10;
279 preconditionerForP_ = std::make_shared<PressJacobi>(pmatrix_, numIterations, 1.0);
283 template<
class Sol,
class Rhs>
284 void applyPreconditionerForA_(Sol& sol, Rhs& rhs)
const
286 preconditionerForA_->pre(sol, rhs);
287 preconditionerForA_->apply(sol, rhs);
288 preconditionerForA_->post(sol);
291 template<
class Sol,
class Rhs>
292 void applyPreconditionerForP_(Sol& sol, Rhs& rhs)
const
294 preconditionerForP_->pre(sol, rhs);
295 preconditionerForP_->apply(sol, rhs);
296 preconditionerForP_->post(sol);
304 const int verbosity_;
306 std::shared_ptr<Dune::Preconditioner<U, U>> preconditionerForA_;
307 std::shared_ptr<Dune::Preconditioner<V, V>> preconditionerForP_;
308 std::shared_ptr<Dune::InverseOperator<U, U>> directSolverForA_;
309 std::shared_ptr<Dune::InverseOperator<V, V>> directSolverForP_;
311 const std::string paramGroup_;
325template<
class Matrix,
class Vector,
class VelocityGG,
class PressureGG>
340 std::shared_ptr<const PressureGG> pGridGeometry,
341 const Vector& dirichletDofs,
344 , vGridGeometry_(std::move(vGridGeometry))
345 , pGridGeometry_(std::move(pGridGeometry))
346 , dirichletDofs_(dirichletDofs)
349 density_ = getParamFromGroup<double>(this->
paramGroup(),
"Component.LiquidDensity");
352 viscosity_ = getParamFromGroup<double>(this->
paramGroup(),
"Component.LiquidDynamicViscosity");
354 viscosity_ = getParamFromGroup<double>(this->
paramGroup(),
"Component.LiquidKinematicViscosity") * density_;
357 const std::string group = this->
paramGroup() ==
"" ?
"Component" : this->
paramGroup() +
".Component";
359 <<
" LiquidDynamicViscosity or LiquidKinematicViscosity"
360 <<
" in parameter group [" << group <<
"]");
363 weight_ = getParamFromGroup<double>(this->
paramGroup(),
"LinearSolver.Preconditioner.MassMatrixWeight", 1.0);
364 solverType_ = getParamFromGroup<std::string>(this->
paramGroup(),
"LinearSolver.Type",
"gmres");
365 scalarProduct_ = std::make_shared<Dune::ScalarProduct<Vector>>();
368 bool solve(
const Matrix& A, Vector& x,
const Vector& b)
373 return applyIterativeSolver_(ATmp, x, bTmp);
378 return scalarProduct_->norm(b);
383 return "Block-preconditioned Stokes solver";
386 const Dune::InverseOperatorResult&
result()
const
392 bool applyIterativeSolver_(Matrix& A, Vector& x, Vector& b)
395 if (getParamFromGroup<bool>(this->
paramGroup(),
"LinearSolver.SymmetrizeDirichlet",
true))
399 using namespace Dune::Indices;
400 A[_1] *= -1.0/density_;
401 b[_1] *= -1.0/density_;
403 auto op = std::make_shared<Dumux::ParallelMultiTypeMatrixAdapter<Matrix, Vector, Vector>>(A);
404 auto pop = makePressureLinearOperator_<typename Preconditioner::PressureLinearOperator>();
405 auto preconditioner = std::make_shared<Preconditioner>(op, pop, params_.sub(
"preconditioner"));
406 params_[
"verbose"] = pGridGeometry_->gridView().comm().rank() == 0 ? params_[
"verbose"] :
"0";
409 std::unique_ptr<Dune::InverseOperator<Vector, Vector>> solver;
410 if (solverType_ ==
"minres")
411 solver = std::make_unique<Dune::MINRESSolver<Vector>>(op, scalarProduct_, preconditioner, params_);
412 else if (solverType_ ==
"bicgstab")
413 solver = std::make_unique<Dune::BiCGSTABSolver<Vector>>(op, scalarProduct_, preconditioner, params_);
414 else if (solverType_ ==
"gmres")
415 solver = std::make_unique<Dune::RestartedGMResSolver<Vector>>(op, scalarProduct_, preconditioner, params_);
417 DUNE_THROW(Dune::NotImplemented,
"Solver choice " << solverType_ <<
" is not implemented");
419 solver->apply(x, b, result_);
421 return result_.converged;
424 template<
class LinearOperator>
425 std::shared_ptr<LinearOperator> makePressureLinearOperator_()
427 using M =
typename LinearOperator::matrix_type;
428 auto massMatrix = createMassMatrix_<M>();
429 return std::make_shared<LinearOperator>(massMatrix);
432 template<
class M,
class DM =
typename PressureGG::DiscretizationMethod>
433 std::shared_ptr<M> createMassMatrix_()
435 auto massMatrix = std::make_shared<M>();
436 massMatrix->setBuildMode(M::random);
437 const auto numDofs = pGridGeometry_->numDofs();
441 Dune::MatrixIndexSet pattern;
442 pattern.resize(numDofs, numDofs);
443 for (
unsigned int globalI = 0; globalI < numDofs; ++globalI)
444 pattern.add(globalI, globalI);
445 pattern.exportIdx(*massMatrix);
447 const auto& gv = pGridGeometry_->gridView();
448 auto fvGeometry =
localView(*pGridGeometry_);
449 for (
const auto& element : elements(gv))
451 fvGeometry.bindElement(element);
452 for (
const auto& scv : scvs(fvGeometry))
454 using Extrusion = Extrusion_t<PressureGG>;
455 const auto dofIndex = scv.dofIndex();
456 if (
element.partitionType() == Dune::GhostEntity)
457 (*massMatrix)[dofIndex][dofIndex] = 1.0;
459 (*massMatrix)[dofIndex][dofIndex] += weight_*
Extrusion::volume(fvGeometry, scv)/(2.0*viscosity_);
467 getJacobianPattern<true>(*pGridGeometry_).exportIdx(*massMatrix);
470 const auto& gv = pGridGeometry_->gridView();
471 auto fvGeometry =
localView(*pGridGeometry_);
472 std::vector<Dune::FieldVector<double, 1>> values;
474 for (
const auto& element : elements(gv))
476 const auto geometry =
element.geometry();
477 const auto& localBasis = pGridGeometry_->feCache().get(
element.type()).localBasis();
478 const auto numLocalDofs = localBasis.size();
479 values.resize(numLocalDofs);
481 fvGeometry.bindElement(element);
482 for (
const auto& scvJ : scvs(fvGeometry))
485 const auto globalJ = scvJ.dofIndex();
487 const auto quadPos = geometry.local(scvJ.center());
488 localBasis.evaluateFunction(quadPos, values);
490 for (
const auto& scvI : scvs(fvGeometry))
492 const auto valueIJ = values[scvI.localDofIndex()]*qWeightJ/(2.0*viscosity_);
493 (*massMatrix)[scvI.dofIndex()][globalJ][0][0] += valueIJ;
501 DUNE_THROW(Dune::NotImplemented,
"Mass matrix for discretization method not implemented");
504 double density_, viscosity_, weight_;
505 Dune::InverseOperatorResult result_;
506 Dune::ParameterTree params_;
507 std::shared_ptr<const VelocityGG> vGridGeometry_;
508 std::shared_ptr<const PressureGG> pGridGeometry_;
509 const Vector& dirichletDofs_;
510 std::string solverType_;
512 std::shared_ptr<Dune::ScalarProduct<Vector>> scalarProduct_;
A Stokes preconditioner (saddle-point problem) for the problem .
Definition: stokes_solver.hh:62
Dune::SolverCategory::Category category() const override
Category of the preconditioner (see SolverCategory::Category)
Definition: stokes_solver.hh:159
X domain_type
The domain type of the preconditioner.
Definition: stokes_solver.hh:78
void post(X &update) override
Clean up.
Definition: stokes_solver.hh:156
typename X::field_type field_type
The field type of the preconditioner.
Definition: stokes_solver.hh:82
Dune::Simd::Scalar< field_type > scalar_field_type
Scalar type underlying the field_type.
Definition: stokes_solver.hh:84
M matrix_type
The matrix type the preconditioner is for.
Definition: stokes_solver.hh:76
Dune::MatrixAdapter< P, V, V > PressureLinearOperator
the type of the pressure operator
Definition: stokes_solver.hh:86
Y range_type
The range type of the preconditioner.
Definition: stokes_solver.hh:80
void pre(X &update, Y ¤tDefect) override
Prepare the preconditioner.
Definition: stokes_solver.hh:121
StokesPreconditioner(const std::shared_ptr< const Dune::AssembledLinearOperator< M, X, Y > > &fullLinearOperator, const std::shared_ptr< const PressureLinearOperator > &pressureLinearOperator, const Dune::ParameterTree ¶ms)
Constructor.
Definition: stokes_solver.hh:94
void apply(X &update, const Y ¤tDefect) override
Apply the preconditioner.
Definition: stokes_solver.hh:134
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
Generates a parameter tree required for the linear solvers and precondioners of the Dune ISTL.
Definition: linearsolverparameters.hh:40
Multi-threaded Jacobi preconditioner.
Definition: preconditioners.hh:331
Exception thrown if a run-time parameter is not specified correctly.
Definition: exceptions.hh:48
Preconditioned iterative solver for the incompressible Stokes problem.
Definition: stokes_solver.hh:328
const Dune::InverseOperatorResult & result() const
Definition: stokes_solver.hh:386
bool solve(const Matrix &A, Vector &x, const Vector &b)
Definition: stokes_solver.hh:368
StokesSolver(std::shared_ptr< const VelocityGG > vGridGeometry, std::shared_ptr< const PressureGG > pGridGeometry, const Vector &dirichletDofs, const std::string ¶mGroup="")
Constructor.
Definition: stokes_solver.hh:339
std::string name() const
Definition: stokes_solver.hh:381
Scalar norm(const Vector &b) const
Definition: stokes_solver.hh:376
Some exceptions thrown in DuMux
Helper classes to compute the integration elements.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
auto volume(const Geometry &geo, unsigned int integrationOrder=4)
The volume of a given geometry.
Definition: volume.hh:159
void symmetrizeConstraints(Dune::BCRSMatrix< MBlock > &A, Vector &b, const Vector &constrainedRows)
Symmetrize the constrained system Ax=b.
Definition: symmetrize_constraints.hh:117
bool hasParamInGroup(const std::string ¶mGroup, const std::string ¶m)
Check whether a key exists in the parameter tree with a model group prefix.
Definition: parameters.hh:165
Helper function to generate Jacobian pattern for different discretization methods.
Generates a parameter tree required for the linear solvers and precondioners of the Dune ISTL.
Define traits for linear solvers.
Define some often used mathematical functions.
Distance implementation details.
Definition: cvfelocalresidual.hh:25
constexpr CCMpfa ccmpfa
Definition: method.hh:146
constexpr FCDiamond fcdiamond
Definition: method.hh:152
constexpr CCTpfa cctpfa
Definition: method.hh:145
constexpr Box box
Definition: method.hh:147
Provides a helper class for nonoverlapping decomposition.
A parallel version of a linear operator.
Dumux preconditioners for iterative solvers.
Base class for linear solvers.
Helper type to determine whether a given type is a Dune::MultiTypeBlockMatrix.
Definition: matrix.hh:37
Helper function to symmetrize row-constraints in constrained linear systems.