24#ifndef DUMUX_LINEAR_PRECONDITIONERS_HH
25#define DUMUX_LINEAR_PRECONDITIONERS_HH
27#include <dune/common/exceptions.hh>
28#include <dune/common/float_cmp.hh>
29#include <dune/common/indices.hh>
30#include <dune/istl/preconditioners.hh>
31#include <dune/istl/paamg/amg.hh>
32#include <dune/common/version.hh>
35#include <dune/istl/umfpack.hh>
41#if DUNE_VERSION_GTE(DUNE_ISTL,2,7)
47#if DUNE_VERSION_GTE(DUNE_ISTL,2,7)
82template<
class M,
class X,
class Y,
int l = 1>
83class SeqUzawa :
public Dune::Preconditioner<X,Y>
86 static_assert(l== 1,
"SeqUzawa expects a block level of 1.");
88 using A = std::decay_t<decltype(std::declval<M>()[Dune::Indices::_0][Dune::Indices::_0])>;
89 using U = std::decay_t<decltype(std::declval<X>()[Dune::Indices::_0])>;
91 using Comm = Dune::Amg::SequentialInformation;
92 using LinearOperator = Dune::MatrixAdapter<A, U, U>;
93 using Smoother = Dune::SeqSSOR<A, U, U>;
94 using AMGSolverForA = Dune::Amg::AMG<LinearOperator, U, Smoother, Comm>;
98 using matrix_type = M;
100 using domain_type = X;
102 using range_type = Y;
104 using field_type =
typename X::field_type;
106 using scalar_field_type = Dune::Simd::Scalar<field_type>;
114#if DUNE_VERSION_GT(DUNE_ISTL,2,7)
115 SeqUzawa(
const std::shared_ptr<
const Dune::AssembledLinearOperator<M,X,Y>>& op,
const Dune::ParameterTree& params)
116 : matrix_(op->getmat())
118 SeqUzawa(const M& mat, const
Dune::ParameterTree& params)
121 , numIterations_(params.get<std::size_t>(
"iterations"))
122 , relaxationFactor_(params.get<scalar_field_type>(
"relaxation"))
123 , verbosity_(params.get<int>(
"verbosity"))
124 , paramGroup_(params.get<std::string>(
"ParameterGroup"))
125 , useDirectVelocitySolverForA_(
getParamFromGroup<bool>(paramGroup_,
"LinearSolver.Preconditioner.DirectSolverForA", false))
127 const bool determineRelaxationFactor = getParamFromGroup<bool>(paramGroup_,
"LinearSolver.Preconditioner.DetermineRelaxationFactor",
true);
130 if (determineRelaxationFactor || !useDirectVelocitySolverForA_)
133 if (useDirectVelocitySolverForA_)
136 if (determineRelaxationFactor)
137 relaxationFactor_ = estimateOmega_();
143 virtual void pre(X& x, Y& b) {}
151 virtual void apply(X& update,
const Y& currentDefect)
153 using namespace Dune::Indices;
155 auto& A = matrix_[_0][_0];
156 auto& B = matrix_[_0][_1];
157 auto& C = matrix_[_1][_0];
158 auto& D = matrix_[_1][_1];
160 const auto& f = currentDefect[_0];
161 const auto& g = currentDefect[_1];
162 auto& u = update[_0];
163 auto& p = update[_1];
167 for (std::size_t i = 0; i < D.N(); ++i)
169 const auto& block = D[i][i];
170 for (
auto rowIt = block.begin(); rowIt != block.end(); ++rowIt)
171 if (Dune::FloatCmp::eq<scalar_field_type>(rowIt->one_norm(), 1.0))
172 p[i][rowIt.index()] = g[i][rowIt.index()];
176 for (std::size_t k = 0; k < numIterations_; ++k)
183 applySolverForA_(uIncrement, uRhs);
188 C.mmv(u, pIncrement);
189 D.mmv(p, pIncrement);
190 pIncrement *= relaxationFactor_;
195 std::cout <<
"Uzawa iteration " << k
196 <<
", residual: " << uRhs.two_norm() + pIncrement.two_norm()/relaxationFactor_ << std::endl;
204 virtual void post(X& x) {}
207 virtual Dune::SolverCategory::Category category()
const
209 return Dune::SolverCategory::sequential;
214 void initAMG_(
const Dune::ParameterTree& params)
216 using namespace Dune::Indices;
217 auto linearOperator = std::make_shared<LinearOperator>(matrix_[_0][_0]);
218 amgSolverForA_ = std::make_unique<AMGSolverForA>(linearOperator, params);
224 using namespace Dune::Indices;
225 umfPackSolverForA_ = std::make_unique<Dune::UMFPack<A>>(matrix_[_0][_0]);
227 DUNE_THROW(Dune::InvalidStateException,
"UMFPack not available. Use LinearSolver.Preconditioner.DirectVelocitySolver = false.");
250 scalar_field_type estimateOmega_()
const
252 using namespace Dune::Indices;
253 auto& A = matrix_[_0][_0];
254 auto& B = matrix_[_0][_1];
255 auto& C = matrix_[_1][_0];
260 scalar_field_type omega = 0.0;
261 scalar_field_type lambdaMax = 0.0;
263 static const auto iterations = Dumux::getParamFromGroup<std::size_t>(paramGroup_,
"LinearSolver.Preconditioner.PowerLawIterations", 5);
266 for (std::size_t i = 0; i < iterations; ++i)
274 applySolverForA_(ainvbx, bx);
282 lambdaMax = x.dot(v)/(x.dot(x));
285 omega = 1.0/lambdaMax;
294 std::cout <<
"\n*** Uzawa Preconditioner ***" << std::endl;
295 std::cout <<
"Estimating relaxation factor based on Schur complement" << std::endl;
296 std::cout <<
"Largest estimated eigenvalue lambdaMax = " << lambdaMax << std::endl;
297 std::cout <<
"Relaxation factor omega = 1/lambdaMax = " << omega << std::endl;
303 template<
class Sol,
class Rhs>
304 void applySolverForA_(Sol& sol, Rhs& rhs)
const
306 if (useDirectVelocitySolverForA_)
309 Dune::InverseOperatorResult res;
310 umfPackSolverForA_->apply(sol, rhs, res);
315 amgSolverForA_->pre(sol, rhs);
316 amgSolverForA_->apply(sol, rhs);
317 amgSolverForA_->post(sol);
324 const std::size_t numIterations_;
326 scalar_field_type relaxationFactor_;
328 const int verbosity_;
330 std::unique_ptr<AMGSolverForA> amgSolverForA_;
332 std::unique_ptr<Dune::UMFPack<A>> umfPackSolverForA_;
334 const std::string paramGroup_;
335 const bool useDirectVelocitySolverForA_;
339#if DUNE_VERSION_GTE(DUNE_ISTL,2,7)
340DUMUX_REGISTER_PRECONDITIONER(
"uzawa", Dumux::MultiTypeBlockMatrixPreconditionerTag, Dune::defaultPreconditionerBlockLevelCreator<Dumux::SeqUzawa, 1>());
Type traits to be used with matrix types.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
The specialized Dumux macro and tag for the ISTL registry to choose the solver and preconditioner at ...
#define DUMUX_REGISTER_PRECONDITIONER(name, tag,...)
Register a Dumux preconditioner.
Definition: istlsolverregistry.hh:44
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition: parameters.hh:375
Definition: common/pdesolver.hh:35
Helper type to determine whether a given type is a Dune::MultiTypeBlockMatrix.
Definition: matrix.hh:49