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"))
 
  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;
 
  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>>
 
  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.");
 
  277            using PressJacobi = Dumux::ParMTJac<P, V, V>;
 
  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)
 
  357            const std::string group = this->
paramGroup() == 
"" ? 
"Component" : this->
paramGroup() + 
".Component";
 
  359                           << 
" LiquidDynamicViscosity or LiquidKinematicViscosity" 
  360                           << 
" in parameter group [" << group << 
"]");
 
  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)
 
  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))
 
  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_);
 
  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();
 
  486                    const auto qWeightJ = PressureGG::Extrusion::volume(fvGeometry, scvJ);
 
  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
const std::string & paramGroup() const
the parameter group for getting parameter from the parameter tree
Definition solver.hh:78
LinearSolver(const std::string ¶mGroup="")
Construct the solver.
Definition solver.hh:43
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
Exception thrown if a run-time parameter is not specified correctly.
Definition exceptions.hh:48
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.
Dune::MatrixIndexSet getJacobianPattern(const GridGeometry &gridGeometry)
Helper function to generate Jacobian pattern for cell-centered methods.
Definition jacobianpattern.hh:28
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition localview.hh:26
void symmetrizeConstraints(Dune::BCRSMatrix< MBlock > &A, Vector &b, const Vector &constrainedRows)
Symmetrize the constrained system Ax=b.
Definition symmetrize_constraints.hh:117
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:149
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
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition extrusion.hh:166
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.