version 3.11-dev
Loading...
Searching...
No Matches
stokes_solver.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-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_LINEAR_STOKES_SOLVER_HH
13#define DUMUX_LINEAR_STOKES_SOLVER_HH
14
15#include <type_traits>
16#include <memory>
17#include <tuple>
18#include <map>
19#include <algorithm>
20#include <cmath>
21
22#include <dune/common/parametertree.hh>
23#include <dune/common/hybridutilities.hh>
24#include <dune/common/exceptions.hh>
25
26#include <dune/istl/matrixindexset.hh>
27#include <dune/istl/preconditioner.hh>
28#include <dune/istl/preconditioners.hh>
29#include <dune/istl/solvers.hh>
30#include <dune/istl/paamg/amg.hh>
31
32#if HAVE_MPI
33#include <dune/istl/owneroverlapcopy.hh>
34#include <dune/istl/schwarz.hh>
35#include <dune/istl/novlpschwarz.hh>
36#endif
37
38#include <dumux/common/math.hh>
49
50namespace Dumux::Detail {
51
52#if HAVE_MPI
55template<class Comm, class Block>
56void makeUnique(const Comm& comm, Block& v)
57{
58 using Attr = Dune::OwnerOverlapCopyAttributeSet;
59 for (const auto& pair : comm.indexSet())
60 if (pair.local().attribute() != Attr::owner)
61 v[pair.local().local()] = 0.0;
62}
63
65template<class Comm, class Block>
66void zeroOverlap(const Comm& comm, Block& v)
67{
68 using Attr = Dune::OwnerOverlapCopyAttributeSet;
69 for (const auto& pair : comm.indexSet())
70 if (pair.local().attribute() == Attr::overlap)
71 v[pair.local().local()] = 0.0;
72}
73
80template<class Comm, class Block>
81void completeCouplingResult(const Comm& comm, Block& y)
82{
83 // on an overlapping decomposition the owned rows are complete already
84 if (comm.category() == Dune::SolverCategory::overlapping)
85 {
86 makeUnique(comm, y);
87 return;
88 }
89
90 zeroOverlap(comm, y);
91 comm.addOwnerCopyToOwnerCopy(y, y);
92 makeUnique(comm, y);
93}
94#endif
95
113template<class M, class X, class Y, int l = 2>
114class StokesPreconditioner : public Dune::Preconditioner<X,Y>
115{
116 static_assert(Dumux::isMultiTypeBlockMatrix<M>::value && M::M() == 2 && M::N() == 2, "Expects a 2x2 MultiTypeBlockMatrix.");
117 static_assert(l == 2, "StokesPreconditioner expects a block level of 2 for Matrix type M.");
118
119 using A = std::decay_t<decltype(std::declval<M>()[Dune::Indices::_0][Dune::Indices::_0])>;
120 using U = std::decay_t<decltype(std::declval<X>()[Dune::Indices::_0])>;
121
122 using P = std::decay_t<decltype(std::declval<M>()[Dune::Indices::_1][Dune::Indices::_1])>;
123 using V = std::decay_t<decltype(std::declval<X>()[Dune::Indices::_1])>;
124
125 enum class Mode { symmetric, triangular, diagonal };
126
127#if HAVE_MPI
128 using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>;
129#endif
130
131public:
133 using matrix_type = M;
135 using domain_type = X;
137 using range_type = Y;
139 using field_type = typename X::field_type;
141 using scalar_field_type = Dune::Simd::Scalar<field_type>;
143 using PressureLinearOperator = Dune::MatrixAdapter<P,V,V>;
144
152 const std::shared_ptr<const Dune::AssembledLinearOperator<M,X,Y>>& fullLinearOperator,
153 const std::shared_ptr<const PressureLinearOperator>& pressureLinearOperator,
154 const Dune::ParameterTree& params
155 )
156 : matrix_(fullLinearOperator->getmat())
157 , pmatrix_(pressureLinearOperator->getmat())
158 , verbosity_(params.get<int>("verbosity"))
159 , paramGroup_(params.get<std::string>("ParameterGroup"))
160 {
161 initMode_(params);
162 initPreconditioner_(params);
163 }
164
165#if HAVE_MPI
175 const std::shared_ptr<const Dune::AssembledLinearOperator<M,X,Y>>& fullLinearOperator,
176 const std::shared_ptr<const PressureLinearOperator>& pressureLinearOperator,
177 const Dune::ParameterTree& params,
178 std::shared_ptr<Comm> velComm,
179 std::shared_ptr<Comm> presComm = nullptr
180 )
181 : matrix_(fullLinearOperator->getmat())
182 , pmatrix_(pressureLinearOperator->getmat())
183 , verbosity_(params.get<int>("verbosity"))
184 , paramGroup_(params.get<std::string>("ParameterGroup"))
185 , velComm_(std::move(velComm))
186 , presComm_(std::move(presComm))
187 {
188 initMode_(params);
189 initPreconditioner_(params);
190 }
191#endif
192
196 void pre(X& update, Y& currentDefect) override
197 {
198 using namespace Dune::Indices;
199 preconditionerForA_->pre(update[_0], currentDefect[_0]);
200 preconditionerForP_->pre(update[_1], currentDefect[_1]);
201 }
202
214 void apply(X& update, const Y& currentDefect) override
215 {
216 using namespace Dune::Indices;
217
218 if (mode_ == Mode::symmetric)
219 {
220 update = applyRightBlock_(currentDefect);
221 update = applyDiagBlock_(update);
222 update = applyLeftBlock_(update);
223 }
224 else if (mode_ == Mode::triangular)
225 {
226 update = applyRightBlock_(currentDefect);
227 update = applyDiagBlock_(update);
228 }
229 else
230 update = applyDiagBlock_(currentDefect);
231 }
232
236 void post(X& update) override
237 {
238 using namespace Dune::Indices;
239 preconditionerForA_->post(update[_0]);
240 preconditionerForP_->post(update[_1]);
241 }
242
244 Dune::SolverCategory::Category category() const override
245 {
246 return Dune::SolverCategory::sequential;
247 }
248
249private:
250 void initMode_(const Dune::ParameterTree& params)
251 {
252 const auto mode = getParamFromGroup<std::string>(
253 paramGroup_, "LinearSolver.Preconditioner.Mode", "Diagonal"
254 );
255
256 auto lower = mode;
257 std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
258 if (lower == "symmetric")
259 mode_ = Mode::symmetric;
260 else if (lower == "triangular")
261 mode_ = Mode::triangular;
262 else
263 mode_ = Mode::diagonal;
264 }
265
266 X applyRightBlock_(const Y& d)
267 {
268 using namespace Dune::Indices;
269
270 // right bit of LDU decomposition
271 // applied to d
272 //
273 // | I 0 |
274 // | -C*inv(A) I |
275 //
276
277 auto dTmp0 = d[_0];
278 auto vTmp = d; vTmp = 0.0;
279
280 // invert velocity block (apply to first block of d), the result is consistent
281 applyPreconditionerForA_(vTmp[_0], dTmp0);
282
283 // then multiply with C, in parallel completed to the unique representation of d[_1]
284 matrix_[_1][_0].mv(vTmp[_0], vTmp[_1]);
285#if HAVE_MPI
286 if (presComm_)
287 completeCouplingResult(*presComm_, vTmp[_1]);
288#endif
289
290 // and subtract from d
291 auto v = d;
292 v[_0] = vTmp[_0]; // already do A^-1 d of the diagonal block because we already computed it here
293 v[_1] -= vTmp[_1];
294 return v;
295 }
296
297 X applyDiagBlock_(const Y& d)
298 {
299 using namespace Dune::Indices;
300
301 // diagonal middle bit of LDU decomposition
302 auto dTmp = d;
303 auto v = d; v = 0.0;
304
305 // invert velocity block
306 if (mode_ == Mode::diagonal)
307 applyPreconditionerForA_(v[_0], dTmp[_0]);
308
309 // reuse the already computed A^-1 d (see applyRightBlock_)
310 else
311 v[_0] = dTmp[_0];
312
313 // invert pressure block
314 applyPreconditionerForP_(v[_1], dTmp[_1]);
315 if (pressureDiagonal_)
316 for (std::size_t i = 0; i < v[_1].size(); ++i)
317 v[_1][i] += (*pressureDiagonal_)[i]*d[_1][i];
318
319 return v;
320 }
321
322 X applyLeftBlock_(const Y& d)
323 {
324 using namespace Dune::Indices;
325
326 // left bit of LDU decomposition
327 // applied to d
328 //
329 // | I -inv(A)*B |
330 // | 0 I |
331 //
332
333 auto dTmp = d;
334 auto vTmp = d; vTmp = 0.0;
335
336 // multiply with B, in parallel completed to the unique defect the velocity preconditioner expects
337 matrix_[_0][_1].umv(dTmp[_1], vTmp[_0]);
338#if HAVE_MPI
339 if (velComm_)
340 completeCouplingResult(*velComm_, vTmp[_0]);
341#endif
342
343 // invert velocity block (apply to first block of d)
344 auto vTmp0 = vTmp[_0]; vTmp0 = 0.0;
345 applyPreconditionerForA_(vTmp0, vTmp[_0]);
346
347 // and subtract from d
348 auto v = d;
349 v[_0] -= vTmp0;
350
351 return v;
352 }
353
354 void initPreconditioner_(const Dune::ParameterTree& params)
355 {
356 using namespace Dune::Indices;
357
358 if (getParamFromGroup<bool>(paramGroup_, "LinearSolver.DirectSolverForVelocity", false))
359 {
360#if HAVE_UMFPACK
361 directSolverForA_ = std::make_shared<Dune::UMFPack<A>>(matrix_[_0][_0], verbosity_);
362 using Wrap = Dune::InverseOperator2Preconditioner<Dune::InverseOperator<U, U>>;
363 preconditionerForA_ = std::make_shared<Wrap>(*directSolverForA_);
364#else
365 DUNE_THROW(Dune::InvalidStateException, "Selected direct solver but UMFPack is not available.");
366#endif
367 }
368 // a few smoothing sweeps suffice where the velocity block is dominated by its storage term
369 else if (getParamFromGroup<bool>(paramGroup_, "LinearSolver.Preconditioner.SSORForVelocity", false))
370 {
371 const auto sweeps = getParamFromGroup<int>(paramGroup_, "LinearSolver.Preconditioner.VelocitySweeps", 2);
372 const auto relaxation = getParamFromGroup<scalar_field_type>(paramGroup_, "LinearSolver.Preconditioner.VelocityRelaxation", 1.0);
373 auto ssor = std::make_shared<Dune::SeqSSOR<A,U,U>>(matrix_[_0][_0], sweeps, relaxation);
374#if HAVE_MPI
375 if (velComm_)
376 {
377 if (velComm_->category() == Dune::SolverCategory::nonoverlapping)
378 preconditionerForA_ = std::make_shared<Dune::NonoverlappingBlockPreconditioner<Comm, Dune::SeqSSOR<A,U,U>>>(ssor, *velComm_);
379 else
380 preconditionerForA_ = std::make_shared<Dune::BlockPreconditioner<U, U, Comm, Dune::SeqSSOR<A,U,U>>>(ssor, *velComm_);
381 }
382 else
383#endif
384 preconditionerForA_ = ssor;
385 }
386 else
387 {
388#if HAVE_MPI
389 if (velComm_)
390 {
391 const bool nonov = (velComm_->category()
392 == Dune::SolverCategory::nonoverlapping);
393 if (nonov)
394 {
395 using VelOp = Dune::NonoverlappingSchwarzOperator<A, U, U, Comm>;
396 using Smoother = Dune::NonoverlappingBlockPreconditioner<Comm, Dune::SeqSSOR<A,U,U>>;
397 auto lopV = std::make_shared<VelOp>(matrix_[_0][_0], *velComm_);
398 preconditionerForA_ = std::make_shared<
399 Dune::Amg::AMG<VelOp, U, Smoother, Comm>>(lopV, params, *velComm_);
400 }
401 else
402 {
403 using VelOp = Dune::OverlappingSchwarzOperator<A, U, U, Comm>;
404 using Smoother = Dune::BlockPreconditioner<U, U, Comm, Dune::SeqSSOR<A,U,U>>;
405 auto lopV = std::make_shared<VelOp>(matrix_[_0][_0], *velComm_);
406 preconditionerForA_ = std::make_shared<
407 Dune::Amg::AMG<VelOp, U, Smoother, Comm>>(lopV, params, *velComm_);
408 }
409 }
410 else
411#endif
412 {
413 using VelLinearOperator = Dune::MatrixAdapter<A, U, U>;
414 auto lopV = std::make_shared<VelLinearOperator>(matrix_[_0][_0]);
415 preconditionerForA_ = std::make_shared<
416 Dune::Amg::AMG<VelLinearOperator, U, Dumux::ParMTSSOR<A,U,U>>
417 >(lopV, params);
418 }
419 }
420
421 if (getParamFromGroup<bool>(paramGroup_, "LinearSolver.DirectSolverForPressure", false))
422 {
423#if HAVE_UMFPACK
424 directSolverForP_ = std::make_shared<Dune::UMFPack<P>>(pmatrix_, verbosity_);
425 using Wrap = Dune::InverseOperator2Preconditioner<Dune::InverseOperator<V, V>>;
426 preconditionerForP_ = std::make_shared<Wrap>(*directSolverForP_);
427#else
428 DUNE_THROW(Dune::InvalidStateException, "Selected direct solver but UMFPack is not available.");
429#endif
430 }
431 // a Poisson-type pressure operator, as for small time steps, needs more than a Jacobi iteration
432 else if (getParamFromGroup<bool>(paramGroup_, "LinearSolver.Preconditioner.AMGForPressure", false))
433 {
434#if HAVE_MPI
435 if (presComm_)
436 {
437 if (presComm_->category() == Dune::SolverCategory::nonoverlapping)
438 {
439 using PressOp = Dune::NonoverlappingSchwarzOperator<P, V, V, Comm>;
440 using Smoother = Dune::NonoverlappingBlockPreconditioner<Comm, Dune::SeqSSOR<P,V,V>>;
441 auto lopP = std::make_shared<PressOp>(pmatrix_, *presComm_);
442 preconditionerForP_ = std::make_shared<
443 Dune::Amg::AMG<PressOp, V, Smoother, Comm>>(lopP, params, *presComm_);
444 }
445 else
446 {
447 using PressOp = Dune::OverlappingSchwarzOperator<P, V, V, Comm>;
448 using Smoother = Dune::BlockPreconditioner<V, V, Comm, Dune::SeqSSOR<P,V,V>>;
449 auto lopP = std::make_shared<PressOp>(pmatrix_, *presComm_);
450 preconditionerForP_ = std::make_shared<
451 Dune::Amg::AMG<PressOp, V, Smoother, Comm>>(lopP, params, *presComm_);
452 }
453 }
454 else
455#endif
456 {
457 auto lopP = std::make_shared<PressureLinearOperator>(pmatrix_);
458 preconditionerForP_ = std::make_shared<
459 Dune::Amg::AMG<PressureLinearOperator, V, Dumux::ParMTSSOR<P,V,V>>
460 >(lopP, params);
461 }
462 }
463 else
464 {
465 const std::size_t numIterations = pmatrix_.nonzeroes() == pmatrix_.N() ? 1 : 10;
466#if HAVE_MPI
467 if (presComm_)
468 {
469 const bool nonovP = (presComm_->category()
470 == Dune::SolverCategory::nonoverlapping);
471 auto seqJacP = std::make_shared<Dune::SeqJac<P,V,V>>(pmatrix_, numIterations, 1.0);
472 if (nonovP)
473 {
474 using PressJacobi = Dune::NonoverlappingBlockPreconditioner<Comm, Dune::SeqJac<P,V,V>>;
475 preconditionerForP_ = std::make_shared<PressJacobi>(seqJacP, *presComm_);
476 }
477 else
478 {
479 using PressJacobi = Dune::BlockPreconditioner<V, V, Comm, Dune::SeqJac<P,V,V>>;
480 preconditionerForP_ = std::make_shared<PressJacobi>(seqJacP, *presComm_);
481 }
482 }
483 else
484#endif
485 {
486 using PressJacobi = Dumux::ParMTJac<P, V, V>;
487 preconditionerForP_ = std::make_shared<PressJacobi>(pmatrix_, numIterations, 1.0);
488 }
489 }
490 }
491
492 template<class Sol, class Rhs>
493 void applyPreconditionerForA_(Sol& sol, Rhs& rhs) const
494 {
495 preconditionerForA_->apply(sol, rhs);
496 }
497
498 template<class Sol, class Rhs>
499 void applyPreconditionerForP_(Sol& sol, Rhs& rhs) const
500 {
501 preconditionerForP_->apply(sol, rhs);
502 }
503
504public:
512 void setPressureDiagonal(std::shared_ptr<const V> diagonal)
513 { pressureDiagonal_ = std::move(diagonal); }
514
515private:
516 std::shared_ptr<const V> pressureDiagonal_;
517
519 const M& matrix_;
521 const P& pmatrix_;
523 const int verbosity_;
524
525 std::shared_ptr<Dune::Preconditioner<U, U>> preconditionerForA_;
526 std::shared_ptr<Dune::Preconditioner<V, V>> preconditionerForP_;
527 std::shared_ptr<Dune::InverseOperator<U, U>> directSolverForA_;
528 std::shared_ptr<Dune::InverseOperator<V, V>> directSolverForP_;
529
530 const std::string paramGroup_;
531 Mode mode_;
532
533#if HAVE_MPI
534 std::shared_ptr<Comm> velComm_;
535 std::shared_ptr<Comm> presComm_;
536#endif
537};
538
539#if HAVE_MPI
540
547template<class M, class X, class Y>
548class ParallelStokesLinearOperator : public Dune::LinearOperator<X, Y>
549{
550 using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>;
551public:
552 using matrix_type = M;
553 using domain_type = X;
554 using range_type = Y;
555 using field_type = typename X::field_type;
556
558 std::shared_ptr<Comm> vComm,
559 std::shared_ptr<Comm> pComm,
560 bool nonOverlapping)
561 : A_(A), localOp_(A), vComm_(std::move(vComm)), pComm_(std::move(pComm))
562 , nonOverlapping_(nonOverlapping)
563 {
564#if HAVE_MPI
565 using namespace Dune::Indices;
566 if (nonOverlapping_)
567 velOp_ = std::make_shared<VelOp>(A_[_0][_0], *vComm_);
568#endif
569 }
570
571 void apply(const X& x, Y& y) const override
572 {
573 using namespace Dune::Indices;
574 if (nonOverlapping_)
575 {
576 applyNonoverlapping_(x, y);
577 }
578 else
579 {
580 // on an overlapping decomposition only the rows of owned dofs are complete
581 localOp_.apply(x, y);
582 makeUnique(*vComm_, y[_0]);
583 makeUnique(*pComm_, y[_1]);
584 }
585 }
586
587 void applyscaleadd(field_type alpha, const X& x, Y& y) const override
588 {
589 using namespace Dune::Indices;
590 Y Ax(y); Ax = 0;
591 apply(x, Ax);
592 y[_0].axpy(alpha, Ax[_0]);
593 y[_1].axpy(alpha, Ax[_1]);
594 }
595
596private:
597 using A00t = std::decay_t<decltype(std::declval<M>()[Dune::Indices::_0][Dune::Indices::_0])>;
598 using Ut = std::decay_t<decltype(std::declval<X>()[Dune::Indices::_0])>;
599 using VelOp = Dune::NonoverlappingSchwarzOperator<A00t, Ut, Ut, Comm>;
600
604 void applyNonoverlapping_(const X& x, Y& y) const
605 {
606 using namespace Dune::Indices;
607
608 X xc(x);
609 vComm_->copyOwnerToAll(xc[_0], xc[_0]);
610 pComm_->copyOwnerToAll(xc[_1], xc[_1]);
611
612 velOp_->apply(xc[_0], y[_0]);
613
614 Ut bv(y[_0]); bv = 0.0;
615 A_[_0][_1].umv(xc[_1], bv);
616 zeroOverlap(*vComm_, bv);
617 vComm_->addOwnerCopyToOwnerCopy(bv, bv);
618 y[_0] += bv;
619
620 // the pressure block is nonzero only in constrained rows, e.g. a pressure pin
621 y[_1] = 0.0;
622 A_[_1][_0].umv(xc[_0], y[_1]);
623 A_[_1][_1].umv(xc[_1], y[_1]);
624 zeroOverlap(*pComm_, y[_1]);
625 pComm_->addOwnerCopyToOwnerCopy(y[_1], y[_1]);
626
627 // the defect b - Ax the preconditioner receives has to be unique (Blatt & Bastian §4.3)
628 makeUnique(*vComm_, y[_0]);
629 makeUnique(*pComm_, y[_1]);
630 }
631
632public:
633
634 Dune::SolverCategory::Category category() const override
635 {
636 return nonOverlapping_ ? Dune::SolverCategory::nonoverlapping
637 : Dune::SolverCategory::overlapping;
638 }
639
640private:
641 const M& A_;
643 std::shared_ptr<Comm> vComm_, pComm_;
644 bool nonOverlapping_;
645 std::shared_ptr<VelOp> velOp_;
646};
647
653template<class SeqPrec, class X, class Y>
654class ParallelStokesPreconditioner : public Dune::Preconditioner<X, Y>
655{
656 using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>;
657public:
658 using domain_type = X;
659 using range_type = Y;
660 using field_type = typename X::field_type;
661
662 ParallelStokesPreconditioner(std::shared_ptr<SeqPrec> seqPrec,
663 std::shared_ptr<Comm> vComm,
664 std::shared_ptr<Comm> pComm,
665 bool nonOverlapping)
666 : seqPrec_(std::move(seqPrec))
667 , vComm_(std::move(vComm)), pComm_(std::move(pComm))
668 , nonOverlapping_(nonOverlapping)
669 {}
670
671 void pre(X& v, Y& d) override
672 {
673 seqPrec_->pre(v, d);
674 communicateUpdate_(v);
675 }
676
677 void apply(X& v, const Y& d) override
678 {
679 seqPrec_->apply(v, d);
680 communicateUpdate_(v);
681 }
682
683 void post(X& v) override
684 {
685 seqPrec_->post(v);
686 communicateUpdate_(v);
687 }
688
689 Dune::SolverCategory::Category category() const override
690 {
691 return nonOverlapping_ ? Dune::SolverCategory::nonoverlapping
692 : Dune::SolverCategory::overlapping;
693 }
694
695private:
696 void communicateUpdate_(X& v)
697 {
698 using namespace Dune::Indices;
699 // the Krylov solver works with consistent vectors; dofs that are not shared,
700 // such as bubble dofs, are not in the index set and need no communication
701 vComm_->copyOwnerToAll(v[_0], v[_0]);
702 pComm_->copyOwnerToAll(v[_1], v[_1]);
703 }
704
705 std::shared_ptr<SeqPrec> seqPrec_;
706 std::shared_ptr<Comm> vComm_, pComm_;
707 bool nonOverlapping_;
708};
709
715template<class X>
716class ParallelStokesScalarProduct : public Dune::ScalarProduct<X>
717{
718 using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>;
719public:
720 using domain_type = X;
721 using field_type = typename X::field_type;
722 using real_type = typename Dune::FieldTraits<field_type>::real_type;
723
724 ParallelStokesScalarProduct(std::shared_ptr<Comm> vComm,
725 std::shared_ptr<Comm> pComm,
726 bool nonOverlapping)
727 : vComm_(std::move(vComm)), pComm_(std::move(pComm))
728 , nonOverlapping_(nonOverlapping)
729 {}
730
731 field_type dot(const X& x, const X& y) const override
732 {
733 using namespace Dune::Indices;
734 using Attr = Dune::OwnerOverlapCopyAttributeSet;
735
736 // dofs that are not shared, such as bubble dofs, are not in the index set,
737 // so sum all local entries and subtract those of shared dofs owned elsewhere
738 field_type local = 0;
739
740 for (std::size_t i = 0; i < x[_0].size(); ++i)
741 local += Dune::dot(x[_0][i], y[_0][i]);
742 for (const auto& pair : vComm_->indexSet())
743 if (pair.local().attribute() != Attr::owner)
744 local -= Dune::dot(x[_0][pair.local()], y[_0][pair.local()]);
745
746 for (std::size_t i = 0; i < x[_1].size(); ++i)
747 local += Dune::dot(x[_1][i], y[_1][i]);
748 for (const auto& pair : pComm_->indexSet())
749 if (pair.local().attribute() != Attr::owner)
750 local -= Dune::dot(x[_1][pair.local()], y[_1][pair.local()]);
751
752 return vComm_->communicator().sum(local);
753 }
754
755 real_type norm(const X& x) const override
756 {
757 using std::sqrt;
758 return sqrt(std::real(dot(x, x)));
759 }
760
761 Dune::SolverCategory::Category category() const override
762 {
763 return nonOverlapping_ ? Dune::SolverCategory::nonoverlapping
764 : Dune::SolverCategory::overlapping;
765 }
766
767
768private:
769 std::shared_ptr<Comm> vComm_, pComm_;
770 bool nonOverlapping_;
771};
772
773#endif // HAVE_MPI
774
775} // end namespace Dumux::Detail
776
777namespace Dumux {
778
785template<class Matrix, class Vector, class VelocityGG, class PressureGG>
787: public LinearSolver
788{
790 using PressureVector = std::decay_t<decltype(std::declval<Vector>()[Dune::Indices::_1])>;
791
792#if HAVE_MPI
793 using VTraits = LinearSolverTraits<VelocityGG>;
794 using PTraits = LinearSolverTraits<PressureGG>;
795 using Comm = Dune::OwnerOverlapCopyCommunication<Dune::bigunsignedint<96>, int>;
796 static constexpr bool canCommunicate_ = VTraits::canCommunicate && PTraits::canCommunicate;
797#endif
798
799public:
802
811 StokesSolver(std::shared_ptr<const VelocityGG> vGridGeometry,
812 std::shared_ptr<const PressureGG> pGridGeometry,
813 const Vector& dirichletDofs,
814 const std::string& paramGroup = "")
816 , vGridGeometry_(std::move(vGridGeometry))
817 , pGridGeometry_(std::move(pGridGeometry))
818 , dirichletDofs_(dirichletDofs)
819 {
820 params_ = LinearSolverParameters<LinearSolverTraits<VelocityGG>>::createParameterTree(this->paramGroup());
821 density_ = getParamFromGroup<double>(this->paramGroup(), "Component.LiquidDensity");
822
823 if (hasParamInGroup(this->paramGroup(), "Component.LiquidDynamicViscosity"))
824 viscosity_ = getParamFromGroup<double>(this->paramGroup(), "Component.LiquidDynamicViscosity");
825 else if (hasParamInGroup(this->paramGroup(), "Component.LiquidKinematicViscosity"))
826 viscosity_ = getParamFromGroup<double>(this->paramGroup(), "Component.LiquidKinematicViscosity") * density_;
827 else
828 {
829 const std::string group = this->paramGroup() == "" ? "Component" : this->paramGroup() + ".Component";
830 DUNE_THROW(ParameterException, "Stokes solver requires the parameters"
831 << " LiquidDynamicViscosity or LiquidKinematicViscosity"
832 << " in parameter group [" << group << "]");
833 }
834
835 weight_ = getParamFromGroup<double>(this->paramGroup(), "LinearSolver.Preconditioner.MassMatrixWeight", 1.0);
836 solverType_ = getParamFromGroup<std::string>(this->paramGroup(), "LinearSolver.Type", "gmres");
837
838 scalarProduct_ = std::make_shared<Dune::ScalarProduct<Vector>>();
839#if HAVE_MPI
840 if constexpr (canCommunicate_)
841 {
842 if (vGridGeometry_->gridView().comm().size() > 1)
843 initParallelInfrastructure_();
844 }
845#endif
846 }
847
848 bool solve(const Matrix& A, Vector& x, const Vector& b)
849 {
850 auto bTmp = b;
851 auto ATmp = A;
852
853 return applyIterativeSolver_(ATmp, x, bTmp);
854 }
855
860 void setMatrix(const Matrix& A)
861 {
862 using namespace Dune::Indices;
863 // the operator and preconditioner refer to the kept matrix
864 keptComponents_ = {};
865 keptMatrix_ = std::make_shared<Matrix>(A);
866 eliminatedEntries_.reset();
867
868 if (symmetrizeDirichlet_())
869 {
870 // the symmetrization moves the known Dirichlet values to the right-hand side; the entries
871 // it eliminates are kept to do the same for every right-hand side passed to solve(x, b)
872 auto unusedRhs = dirichletDofs_;
873 symmetrizeConstraints(*keptMatrix_, unusedRhs, dirichletDofs_);
874 eliminatedEntries_ = std::make_shared<Matrix>(A);
875 *eliminatedEntries_ -= *keptMatrix_;
876 }
877
878 (*keptMatrix_)[_1] *= -1.0/density_;
879
880#if HAVE_MPI
881 if constexpr (canCommunicate_)
882 {
883 if (vGridGeometry_->gridView().comm().size() > 1 && isNonOverlapping_)
884 prepareParallelMatrix_(*keptMatrix_);
885 }
886#endif
887
888 keptComponents_ = makeSolverComponents_(*keptMatrix_);
889 }
890
892 void setMatrix(std::shared_ptr<Matrix> A)
893 { setMatrix(*A); }
894
896 bool solve(Vector& x, const Vector& b)
897 {
898 if (!keptMatrix_)
899 DUNE_THROW(Dune::InvalidStateException, "Called solve(x, b) but no matrix has been set");
900
901 using namespace Dune::Indices;
902 auto bTmp = b;
903 if (eliminatedEntries_)
904 {
905 auto dirichletValues = b;
906 Dune::Hybrid::forEach(std::make_index_sequence<Vector::size()>{}, [&](auto i)
907 {
908 for (std::size_t k = 0; k < dirichletValues[i].size(); ++k)
909 for (std::size_t c = 0; c < dirichletValues[i][k].size(); ++c)
910 dirichletValues[i][k][c] *= dirichletDofs_[i][k][c];
911 });
912 eliminatedEntries_->mmv(dirichletValues, bTmp);
913 }
914
915 bTmp[_1] *= -1.0/density_;
916
917#if HAVE_MPI
918 if constexpr (canCommunicate_)
919 {
920 if (vGridGeometry_->gridView().comm().size() > 1)
921 {
922 prepareParallelRhs_(bTmp);
923 const bool converged = runSolver_(keptComponents_.op, scalarProduct_, keptComponents_.preconditioner, x, bTmp);
925 return converged;
926 }
927 }
928#endif
929 return runSolver_(keptComponents_.op, scalarProduct_, keptComponents_.preconditioner, x, bTmp);
930 }
931
943 void setPressureMatrix(std::shared_ptr<const PressureMatrix> matrix)
944 { pressureMatrix_ = std::move(matrix); }
945
947 void setPressureDiagonal(std::shared_ptr<const PressureVector> diagonal)
948 { pressureDiagonal_ = std::move(diagonal); }
949
951 void makeConsistent(Vector& v) const
952 {
953#if HAVE_MPI
954 using namespace Dune::Indices;
955 if (vComm_ && pComm_)
956 {
957 vComm_->copyOwnerToAll(v[_0], v[_0]);
958 pComm_->copyOwnerToAll(v[_1], v[_1]);
959 }
960#endif
961 }
962
964 void makeUnique(Vector& v) const
965 {
966#if HAVE_MPI
967 using namespace Dune::Indices;
968 if (vComm_ && pComm_)
969 {
970 Detail::makeUnique(*vComm_, v[_0]);
971 Detail::makeUnique(*pComm_, v[_1]);
972 }
973#endif
974 }
975
976 Scalar norm(const Vector& b) const
977 {
978#if HAVE_MPI
979 // on a non-overlapping decomposition an assembled residual is additive, so the owned entries
980 // are only complete after summing over the processes; on an overlapping one they are complete
981 using namespace Dune::Indices;
982 if (vComm_ && pComm_ && vGridGeometry_->gridView().comm().size() > 1)
983 {
984 Vector bc(b);
985 if (isNonOverlapping_)
986 {
987 vComm_->addOwnerCopyToOwnerCopy(bc[_0], bc[_0]);
988 pComm_->addOwnerCopyToOwnerCopy(bc[_1], bc[_1]);
989 }
990 else
991 {
992 Detail::makeUnique(*vComm_, bc[_0]);
993 Detail::makeUnique(*pComm_, bc[_1]);
994 }
995 return scalarProduct_->norm(bc);
996 }
997#endif
998 return scalarProduct_->norm(b);
999 }
1000
1001 std::string name() const
1002 {
1003 return "Block-preconditioned Stokes solver";
1004 }
1005
1006 const Dune::InverseOperatorResult& result() const
1007 {
1008 return result_;
1009 }
1010
1011private:
1012#if HAVE_MPI
1013 void initParallelInfrastructure_()
1014 {
1015 // if either sub-problem is overlapping, use overlapping for both
1016 isNonOverlapping_ = VTraits::isNonOverlapping(vGridGeometry_->gridView())
1017 && PTraits::isNonOverlapping(pGridGeometry_->gridView());
1018
1019 const auto cat = isNonOverlapping_ ? Dune::SolverCategory::nonoverlapping
1020 : Dune::SolverCategory::overlapping;
1021
1022 // the helpers keep a reference to the dof mapper, which the traits may return by value
1023 vDofMapper_ = std::make_shared<const typename VTraits::DofMapper>(VTraits::dofMapper(*vGridGeometry_));
1024 pDofMapper_ = std::make_shared<const typename PTraits::DofMapper>(PTraits::dofMapper(*pGridGeometry_));
1025 vParallelHelper_ = std::make_shared<ParallelISTLHelper<VTraits>>(vGridGeometry_->gridView(), *vDofMapper_);
1026 pParallelHelper_ = std::make_shared<ParallelISTLHelper<PTraits>>(pGridGeometry_->gridView(), *pDofMapper_);
1027
1028 vComm_ = std::make_shared<Comm>(vGridGeometry_->gridView().comm(), cat);
1029 vParallelHelper_->createParallelIndexSet(*vComm_);
1030
1031 pComm_ = std::make_shared<Comm>(pGridGeometry_->gridView().comm(), cat);
1032 pParallelHelper_->createParallelIndexSet(*pComm_);
1033
1034 scalarProduct_ = std::make_shared<Detail::ParallelStokesScalarProduct<Vector>>(
1035 vComm_, pComm_, isNonOverlapping_);
1036 }
1037#endif
1038
1039 bool symmetrizeDirichlet_() const
1040 { return getParamFromGroup<bool>(this->paramGroup(), "LinearSolver.SymmetrizeDirichlet", true); }
1041
1042 bool applyIterativeSolver_(Matrix& A, Vector& x, Vector& b)
1043 {
1044 // make Dirichlet boundary conditions symmetric
1045 if (symmetrizeDirichlet_())
1046 symmetrizeConstraints(A, b, dirichletDofs_);
1047
1048 // make Matrix symmetric on the block-scale
1049 using namespace Dune::Indices;
1050 A[_1] *= -1.0/density_;
1051 b[_1] *= -1.0/density_;
1052
1053#if HAVE_MPI
1054 if constexpr (canCommunicate_)
1055 {
1056 if (vGridGeometry_->gridView().comm().size() > 1)
1057 {
1058 if (isNonOverlapping_)
1059 prepareParallelMatrix_(A);
1060 prepareParallelRhs_(b);
1061 const auto components = makeSolverComponents_(A);
1062 const bool converged = runSolver_(components.op, scalarProduct_, components.preconditioner, x, b);
1063 makeConsistent(x);
1064 return converged;
1065 }
1066 }
1067#endif
1068 const auto components = makeSolverComponents_(A);
1069 return runSolver_(components.op, scalarProduct_, components.preconditioner, x, b);
1070 }
1071
1073 struct SolverComponents
1074 {
1075 std::shared_ptr<Dune::LinearOperator<Vector, Vector>> op;
1076 std::shared_ptr<Dune::Preconditioner<Vector, Vector>> preconditioner;
1077 // the preconditioner refers to the matrix of the pressure operator
1078 std::shared_ptr<typename Preconditioner::PressureLinearOperator> pressureOperator;
1079 };
1080
1081 SolverComponents makeSolverComponents_(const Matrix& A)
1082 {
1083 SolverComponents components;
1084 components.pressureOperator = makePressureLinearOperator_<typename Preconditioner::PressureLinearOperator>();
1085 auto assembledOperator = std::make_shared<Dumux::ParallelMultiTypeMatrixAdapter<Matrix, Vector, Vector>>(A);
1086
1087#if HAVE_MPI
1088 if constexpr (canCommunicate_)
1089 {
1090 if (vGridGeometry_->gridView().comm().size() > 1)
1091 {
1092 // the preconditioner needs the assembled operator, the Krylov solver the parallel one
1093 components.op = std::make_shared<Detail::ParallelStokesLinearOperator<Matrix, Vector, Vector>>(
1094 A, vComm_, pComm_, isNonOverlapping_);
1095 auto preconditioner = std::make_shared<Preconditioner>(
1096 assembledOperator, components.pressureOperator, params_.sub("preconditioner"), vComm_, pComm_);
1097 preconditioner->setPressureDiagonal(pressureDiagonal_);
1098 components.preconditioner = std::make_shared<Detail::ParallelStokesPreconditioner<Preconditioner, Vector, Vector>>(
1099 preconditioner, vComm_, pComm_, isNonOverlapping_);
1100 return components;
1101 }
1102 }
1103#endif
1104
1105 auto preconditioner = std::make_shared<Preconditioner>(assembledOperator, components.pressureOperator, params_.sub("preconditioner"));
1106 preconditioner->setPressureDiagonal(pressureDiagonal_);
1107 components.op = assembledOperator;
1108 components.preconditioner = preconditioner;
1109 return components;
1110 }
1111
1112#if HAVE_MPI
1113 void prepareParallelMatrix_(Matrix& A)
1114 {
1115 using namespace Dune::Indices;
1116 using GridView = typename VelocityGG::GridView;
1117 static constexpr int dim = GridView::dimension;
1118 static constexpr std::size_t numCodims = dim + 1;
1119
1120 const auto& gv = vGridGeometry_->gridView();
1121 const auto velCodims = activeCodimsBitset_<VTraits, numCodims>();
1122
1123 // the velocity block is summed over the processes: the smoother of the velocity AMG needs
1124 // complete diagonal entries; the off-diagonal blocks stay additive (see ParallelStokesLinearOperator)
1125 using VelBlock = std::decay_t<decltype(A[_0][_0])>;
1126 MultiCodimParallelMatrixHelper<VelBlock, GridView, typename VTraits::DofMapper, numCodims>
1127 velHelper(gv, *vDofMapper_, velCodims);
1128 velHelper.extendMatrix(A[_0][_0], [](auto){ return false; });
1129 velHelper.sumEntries(A[_0][_0]);
1130 }
1131
1133 void prepareParallelRhs_(Vector& b)
1134 {
1135 using namespace Dune::Indices;
1136 if (isNonOverlapping_)
1137 {
1138 using VelVec = std::decay_t<decltype(b[_0])>;
1139 using PresVec = std::decay_t<decltype(b[_1])>;
1140 using VNonoverlapping = typename VTraits::template ParallelNonoverlapping<
1141 std::decay_t<decltype(std::declval<Matrix>()[_0][_0])>, VelVec>;
1142 using PNonoverlapping = typename PTraits::template ParallelNonoverlapping<
1143 std::decay_t<decltype(std::declval<Matrix>()[_1][_1])>, PresVec>;
1144 prepareVectorParallel<VTraits, VNonoverlapping>(b[_0], *vParallelHelper_);
1145 prepareVectorParallel<PTraits, PNonoverlapping>(b[_1], *pParallelHelper_);
1146 }
1147
1148 Detail::makeUnique(*vComm_, b[_0]);
1149 Detail::makeUnique(*pComm_, b[_1]);
1150 }
1151
1152 // Returns active codims as bitset<numCodims> from a LinearSolverTraits type.
1153 template<class Traits, std::size_t numCodims>
1154 static std::bitset<numCodims> activeCodimsBitset_()
1155 {
1156 if constexpr (requires { Traits::dofCodims; })
1157 return Traits::dofCodims;
1158 else
1159 {
1160 std::bitset<numCodims> bits;
1161 bits.set(Traits::dofCodim);
1162 return bits;
1163 }
1164 }
1165#endif // HAVE_MPI
1166
1167 template<class LinearOperator, class SP, class Prec>
1168 bool runSolver_(std::shared_ptr<LinearOperator> op,
1169 std::shared_ptr<SP> sp,
1170 std::shared_ptr<Prec> prec,
1171 Vector& x, Vector& b)
1172 {
1173 std::unique_ptr<Dune::InverseOperator<Vector, Vector>> solver;
1174 if (solverType_ == "minres")
1175 solver = std::make_unique<Dune::MINRESSolver<Vector>>(op, sp, prec, params_);
1176 else if (solverType_ == "bicgstab")
1177 solver = std::make_unique<Dune::BiCGSTABSolver<Vector>>(op, sp, prec, params_);
1178 else if (solverType_ == "gmres")
1179 solver = std::make_unique<Dune::RestartedGMResSolver<Vector>>(op, sp, prec, params_);
1180 else
1181 DUNE_THROW(Dune::NotImplemented, "Solver choice " << solverType_ << " is not implemented");
1182
1183 solver->apply(x, b, result_);
1184 return result_.converged;
1185 }
1186
1187 template<class LinearOperator>
1188 std::shared_ptr<LinearOperator> makePressureLinearOperator_()
1189 {
1190 if (pressureMatrix_)
1191 return std::make_shared<LinearOperator>(pressureMatrix_);
1192
1193 using M = typename LinearOperator::matrix_type;
1194 auto massMatrix = createMassMatrix_<M>();
1195 return std::make_shared<LinearOperator>(massMatrix);
1196 }
1197
1198 template<class M, class DM = typename PressureGG::DiscretizationMethod>
1199 std::shared_ptr<M> createMassMatrix_()
1200 {
1201 auto massMatrix = std::make_shared<M>();
1202 massMatrix->setBuildMode(M::random);
1203 const auto numDofs = pGridGeometry_->numDofs();
1204
1205 if constexpr (DM{} == DiscretizationMethods::cctpfa || DM{} == DiscretizationMethods::ccmpfa)
1206 {
1207 Dune::MatrixIndexSet pattern;
1208 pattern.resize(numDofs, numDofs);
1209 for (unsigned int globalI = 0; globalI < numDofs; ++globalI)
1210 pattern.add(globalI, globalI);
1211 pattern.exportIdx(*massMatrix);
1212
1213 const auto& gv = pGridGeometry_->gridView();
1214 auto fvGeometry = localView(*pGridGeometry_);
1215 for (const auto& element : elements(gv))
1216 {
1217 fvGeometry.bindElement(element);
1218 for (const auto& scv : scvs(fvGeometry))
1219 {
1220 using Extrusion = Extrusion_t<PressureGG>;
1221 const auto dofIndex = scv.dofIndex();
1222 if (element.partitionType() == Dune::GhostEntity) // do not modify ghosts
1223 (*massMatrix)[dofIndex][dofIndex][0][0] = 1.0;
1224 else
1225 (*massMatrix)[dofIndex][dofIndex][0][0] += weight_*Extrusion::volume(fvGeometry, scv)/(2.0*viscosity_);
1226 }
1227 }
1228
1229 return massMatrix;
1230 }
1231 else if constexpr (DM{} == DiscretizationMethods::box || DM{} == DiscretizationMethods::fcdiamond)
1232 {
1233 getJacobianPattern<true>(*pGridGeometry_).exportIdx(*massMatrix);
1234 (*massMatrix) = 0.0;
1235
1236 const auto& gv = pGridGeometry_->gridView();
1237 auto fvGeometry = localView(*pGridGeometry_);
1238 std::vector<Dune::FieldVector<double, 1>> values;
1239
1240 for (const auto& element : elements(gv))
1241 {
1242 const auto geometry = element.geometry();
1243 const auto& localBasis = pGridGeometry_->feCache().get(element.type()).localBasis();
1244 const auto numLocalDofs = localBasis.size();
1245 values.resize(numLocalDofs);
1246
1247 fvGeometry.bindElement(element);
1248 for (const auto& scvJ : scvs(fvGeometry))
1249 {
1250 // Use mid-point rule (only works for linear ansatz functions)
1251 const auto globalJ = scvJ.dofIndex();
1252 const auto qWeightJ = PressureGG::Extrusion::volume(fvGeometry, scvJ);
1253 const auto quadPos = geometry.local(scvJ.center());
1254 localBasis.evaluateFunction(quadPos, values);
1255
1256 for (const auto& scvI : scvs(fvGeometry))
1257 {
1258 const auto valueIJ = values[scvI.localDofIndex()]*qWeightJ/(2.0*viscosity_);
1259 (*massMatrix)[scvI.dofIndex()][globalJ][0][0] += valueIJ;
1260 }
1261 }
1262 }
1263
1264#if HAVE_MPI
1265 // on a non-overlapping decomposition the mass of a border dof is summed over the processes
1266 if (pGridGeometry_->gridView().comm().size() > 1 && isNonOverlapping_ && pParallelHelper_)
1267 {
1268 using PNonoverlapping = typename PTraits::template ParallelNonoverlapping<
1269 M, std::decay_t<decltype((*massMatrix)[0])>>;
1270 prepareMatrixParallel<PTraits, PNonoverlapping>(*massMatrix, *pParallelHelper_);
1271 }
1272#endif
1273
1274 return massMatrix;
1275 }
1276
1277 DUNE_THROW(Dune::NotImplemented, "Mass matrix for discretization method not implemented");
1278 }
1279
1280 double density_, viscosity_, weight_;
1281 Dune::InverseOperatorResult result_;
1282 Dune::ParameterTree params_;
1283 std::shared_ptr<const VelocityGG> vGridGeometry_;
1284 std::shared_ptr<const PressureGG> pGridGeometry_;
1285 const Vector& dirichletDofs_;
1286 std::string solverType_;
1287
1288 std::shared_ptr<Dune::ScalarProduct<Vector>> scalarProduct_;
1289
1290 std::shared_ptr<const PressureMatrix> pressureMatrix_;
1291 std::shared_ptr<const PressureVector> pressureDiagonal_;
1292 std::shared_ptr<Matrix> keptMatrix_;
1293 std::shared_ptr<Matrix> eliminatedEntries_;
1294 SolverComponents keptComponents_;
1295
1296#if HAVE_MPI
1297 std::shared_ptr<const typename VTraits::DofMapper> vDofMapper_;
1298 std::shared_ptr<const typename PTraits::DofMapper> pDofMapper_;
1299 std::shared_ptr<ParallelISTLHelper<VTraits>> vParallelHelper_;
1300 std::shared_ptr<ParallelISTLHelper<PTraits>> pParallelHelper_;
1301 std::shared_ptr<Comm> vComm_, pComm_;
1302 bool isNonOverlapping_ = true;
1303#endif
1304};
1305
1306} // end namespace Dumux
1307
1308#endif
Dune::SolverCategory::Category category() const override
Definition stokes_solver.hh:634
void applyscaleadd(field_type alpha, const X &x, Y &y) const override
Definition stokes_solver.hh:587
void apply(const X &x, Y &y) const override
Definition stokes_solver.hh:571
X domain_type
Definition stokes_solver.hh:553
M matrix_type
Definition stokes_solver.hh:552
ParallelStokesLinearOperator(const M &A, std::shared_ptr< Comm > vComm, std::shared_ptr< Comm > pComm, bool nonOverlapping)
Definition stokes_solver.hh:557
Y range_type
Definition stokes_solver.hh:554
typename X::field_type field_type
Definition stokes_solver.hh:555
void apply(X &v, const Y &d) override
Definition stokes_solver.hh:677
void pre(X &v, Y &d) override
Definition stokes_solver.hh:671
void post(X &v) override
Definition stokes_solver.hh:683
ParallelStokesPreconditioner(std::shared_ptr< SeqPrec > seqPrec, std::shared_ptr< Comm > vComm, std::shared_ptr< Comm > pComm, bool nonOverlapping)
Definition stokes_solver.hh:662
Dune::SolverCategory::Category category() const override
Definition stokes_solver.hh:689
X domain_type
Definition stokes_solver.hh:658
Y range_type
Definition stokes_solver.hh:659
typename X::field_type field_type
Definition stokes_solver.hh:660
X domain_type
Definition stokes_solver.hh:720
typename Dune::FieldTraits< field_type >::real_type real_type
Definition stokes_solver.hh:722
ParallelStokesScalarProduct(std::shared_ptr< Comm > vComm, std::shared_ptr< Comm > pComm, bool nonOverlapping)
Definition stokes_solver.hh:724
field_type dot(const X &x, const X &y) const override
Definition stokes_solver.hh:731
Dune::SolverCategory::Category category() const override
Definition stokes_solver.hh:761
real_type norm(const X &x) const override
Definition stokes_solver.hh:755
typename X::field_type field_type
Definition stokes_solver.hh:721
A Stokes preconditioner (saddle-point problem) for the problem .
Definition stokes_solver.hh:115
Dune::SolverCategory::Category category() const override
Category of the preconditioner (see SolverCategory::Category).
Definition stokes_solver.hh:244
StokesPreconditioner(const std::shared_ptr< const Dune::AssembledLinearOperator< M, X, Y > > &fullLinearOperator, const std::shared_ptr< const PressureLinearOperator > &pressureLinearOperator, const Dune::ParameterTree &params, std::shared_ptr< Comm > velComm, std::shared_ptr< Comm > presComm=nullptr)
Constructor (parallel).
Definition stokes_solver.hh:174
X domain_type
The domain type of the preconditioner.
Definition stokes_solver.hh:135
void post(X &update) override
Clean up the preconditioners of the velocity and the pressure block.
Definition stokes_solver.hh:236
typename X::field_type field_type
The field type of the preconditioner.
Definition stokes_solver.hh:139
Dune::Simd::Scalar< field_type > scalar_field_type
Scalar type underlying the field_type.
Definition stokes_solver.hh:141
M matrix_type
The matrix type the preconditioner is for.
Definition stokes_solver.hh:133
Dune::MatrixAdapter< P, V, V > PressureLinearOperator
the type of the pressure operator
Definition stokes_solver.hh:143
void setPressureDiagonal(std::shared_ptr< const V > diagonal)
Add a diagonal to the inverse of the pressure block.
Definition stokes_solver.hh:512
Y range_type
The range type of the preconditioner.
Definition stokes_solver.hh:137
void pre(X &update, Y &currentDefect) override
Prepare the preconditioners of the velocity and the pressure block.
Definition stokes_solver.hh:196
StokesPreconditioner(const std::shared_ptr< const Dune::AssembledLinearOperator< M, X, Y > > &fullLinearOperator, const std::shared_ptr< const PressureLinearOperator > &pressureLinearOperator, const Dune::ParameterTree &params)
Constructor (sequential).
Definition stokes_solver.hh:151
void apply(X &update, const Y &currentDefect) override
Apply the preconditioner.
Definition stokes_solver.hh:214
const std::string & paramGroup() const
the parameter group for getting parameter from the parameter tree
Definition solver.hh:78
LinearSolver(const std::string &paramGroup="")
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
Adapter to turn a multi-type matrix into a thread-parallel linear operator. Adapts a matrix to the as...
Definition parallelmatrixadapter.hh:28
Exception thrown if a run-time parameter is not specified correctly.
Definition exceptions.hh:48
void setMatrix(const Matrix &A)
Keep a copy of the matrix, and the operator and preconditioner built on it, for solve(x,...
Definition stokes_solver.hh:860
void makeConsistent(Vector &v) const
Give the copies of shared degrees of freedom the values of their owners.
Definition stokes_solver.hh:951
bool solve(Vector &x, const Vector &b)
Solve with the matrix kept by setMatrix.
Definition stokes_solver.hh:896
void setPressureDiagonal(std::shared_ptr< const PressureVector > diagonal)
Set the diagonal added to the inverse of the pressure block (see StokesPreconditioner::setPressureDia...
Definition stokes_solver.hh:947
const Dune::InverseOperatorResult & result() const
Definition stokes_solver.hh:1006
bool solve(const Matrix &A, Vector &x, const Vector &b)
Definition stokes_solver.hh:848
void makeUnique(Vector &v) const
Set the entries of shared degrees of freedom this process does not own to zero.
Definition stokes_solver.hh:964
StokesSolver(std::shared_ptr< const VelocityGG > vGridGeometry, std::shared_ptr< const PressureGG > pGridGeometry, const Vector &dirichletDofs, const std::string &paramGroup="")
Constructor.
Definition stokes_solver.hh:811
std::string name() const
Definition stokes_solver.hh:1001
void setMatrix(std::shared_ptr< Matrix > A)
Keep a copy of the matrix, and the operator and preconditioner built on it, for solve(x,...
Definition stokes_solver.hh:892
void setPressureMatrix(std::shared_ptr< const PressureMatrix > matrix)
Use the given matrix in place of the pressure mass matrix in the preconditioner.
Definition stokes_solver.hh:943
typename Preconditioner::PressureLinearOperator::matrix_type PressureMatrix
The matrix type of the pressure operator of the preconditioner.
Definition stokes_solver.hh:801
Scalar norm(const Vector &b) const
Definition stokes_solver.hh:976
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
@ element
Definition fieldtype.hh:23
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:165
bool hasParamInGroup(const std::string &paramGroup, const std::string &param)
Check whether a key exists in the parameter tree with a model group prefix.
Definition parameters.hh:181
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.
Definition cvfelocalresidual.hh:25
void completeCouplingResult(const Comm &comm, Block &y)
Complete the product y = M x of an off-diagonal block M with a consistent x to the unique representat...
Definition stokes_solver.hh:81
void zeroOverlap(const Comm &comm, Block &v)
Set the entries of overlap dofs to zero.
Definition stokes_solver.hh:66
void makeUnique(const Comm &comm, Block &v)
Definition stokes_solver.hh:56
constexpr CCMpfa ccmpfa
Definition method.hh:175
constexpr FCDiamond fcdiamond
Definition method.hh:184
constexpr CCTpfa cctpfa
Definition method.hh:174
constexpr Box box
Definition method.hh:176
Definition adapt.hh:17
void prepareMatrixParallel(Matrix &A, ParallelHelper &pHelper)
Prepare a matrix for parallel solvers.
Definition parallelhelpers.hh:1410
LinearSolverTraitsImpl< GridGeometry, typename GridGeometry::DiscretizationMethod > LinearSolverTraits
The type traits required for using the IstlFactoryBackend.
Definition linearsolvertraits.hh:39
void prepareVectorParallel(Vector &b, ParallelHelper &pHelper)
Prepare a vector for parallel solvers.
Definition parallelhelpers.hh:1441
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition localdof.hh:82
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition extrusion.hh:257
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.