amgcpr.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_AMG_AMG_CPR_HH
4#define DUNE_AMG_AMG_CPR_HH
5
6// NOTE: This file is a modified version of dune/istl/paamg/amg.hh from
7// dune-istl release 2.6.0. Modifications have been kept as minimal as possible.
8
10#include <opm/common/TimingMacros.hpp>
11#include <dune/common/exceptions.hh>
12#include <dune/common/version.hh>
13#include <dune/istl/paamg/amg.hh>
14#include <dune/istl/paamg/smoother.hh>
15#include <dune/istl/paamg/transfer.hh>
16#include <dune/istl/paamg/hierarchy.hh>
17#include <dune/istl/solvers.hh>
18#include <dune/istl/scalarproducts.hh>
19#include <dune/istl/superlu.hh>
20#include <dune/istl/umfpack.hh>
21#include <dune/istl/solvertype.hh>
22#include <dune/common/typetraits.hh>
23#include <dune/common/exceptions.hh>
24
25#include <memory>
26
27namespace Dune
28{
29 namespace Amg
30 {
31
32
33#if HAVE_MPI
34 template<class M, class T>
35 void redistributeMatrixAmg(M&, M&, SequentialInformation&, SequentialInformation&, T&)
36 {
37 // noop
38 }
39
40 template<class M, class PI>
41 typename std::enable_if<!std::is_same<PI,SequentialInformation>::value,void>::type
42 redistributeMatrixAmg(M& mat, M& matRedist, PI& info, PI& infoRedist,
43 Dune::RedistributeInformation<PI>& redistInfo)
44 {
45 OPM_TIMEBLOCK(redistributeMatrixAmg);
46 info.buildGlobalLookup(mat.N());
47 redistributeMatrixEntries(mat, matRedist, info, infoRedist, redistInfo);
48 info.freeGlobalLookup();
49 }
50#endif
51
69 template<class M, class X, class S, class P, class K, class A>
70 class KAMG;
71
72 template<class T>
74
85 template<class M, class X, class S, class PI=SequentialInformation,
86 class A=std::allocator<X> >
87 class AMGCPR : public PreconditionerWithUpdate<X,X>
88 {
89 template<class M1, class X1, class S1, class P1, class K1, class A1>
90 friend class KAMG;
91
92 friend class KAmgTwoGrid<AMGCPR>;
93
94 public:
96 typedef M Operator;
105 typedef MatrixHierarchy<M, ParallelInformation, A> OperatorHierarchy;
107 typedef typename OperatorHierarchy::ParallelInformationHierarchy ParallelInformationHierarchy;
108
110 typedef X Domain;
112 typedef X Range;
114 typedef InverseOperator<X,X> CoarseSolver;
120 typedef S Smoother;
121
123 typedef typename SmootherTraits<Smoother>::Arguments SmootherArgs;
124
134 AMGCPR(const OperatorHierarchy& matrices, CoarseSolver& coarseSolver,
135 const SmootherArgs& smootherArgs, const Parameters& parms);
136
148 template<class C>
149 AMGCPR(const Operator& fineOperator, const C& criterion,
150 const SmootherArgs& smootherArgs=SmootherArgs(),
152
156 AMGCPR(const AMGCPR& amg);
157
158 ~AMGCPR();
159
161 void pre(Domain& x, Range& b) override;
162
164 void apply(Domain& v, const Range& d) override;
165
167 SolverCategory::Category category() const override
168 {
169 return category_;
170 }
171
172 bool hasPerfectUpdate() const override
173 {
174 return false;
175 }
176
178 void post(Domain& x) override;
179
184 template<class A1>
185 void getCoarsestAggregateNumbers(std::vector<std::size_t,A1>& cont);
186
187 std::size_t levels();
188
189 std::size_t maxlevels();
190
200 {
201 OPM_TIMEBLOCK(recalculateHierarch);
202 auto copyFlags = NegateSet<typename PI::OwnerSet>();
203 const auto& matrices = matrices_->matrices();
204 const auto& aggregatesMapHierarchy = matrices_->aggregatesMaps();
205 const auto& infoHierarchy = matrices_->parallelInformation();
206 const auto& redistInfoHierarchy = matrices_->redistributeInformation();
207 BaseGalerkinProduct productBuilder;
208 auto aggregatesMap = aggregatesMapHierarchy.begin();
209 auto info = infoHierarchy.finest();
210 auto redistInfo = redistInfoHierarchy.begin();
211 auto matrix = matrices.finest();
212 auto coarsestMatrix = matrices.coarsest();
213
214 using Matrix = typename M::matrix_type;
215
216#if HAVE_MPI
217 if(matrix.isRedistributed()) {
218 redistributeMatrixAmg(const_cast<Matrix&>(matrix->getmat()),
219 const_cast<Matrix&>(matrix.getRedistributed().getmat()),
220 const_cast<PI&>(*info), const_cast<PI&>(info.getRedistributed()),
221 const_cast<Dune::RedistributeInformation<PI>&>(*redistInfo));
222 }
223#endif
224
225 for(; matrix!=coarsestMatrix; ++aggregatesMap) {
226 const Matrix& fine = (matrix.isRedistributed() ? matrix.getRedistributed() : *matrix).getmat();
227 ++matrix;
228 ++info;
229 ++redistInfo;
230 productBuilder.calculate(fine, *(*aggregatesMap), const_cast<Matrix&>(matrix->getmat()), *info, copyFlags);
231#if HAVE_MPI
232 if(matrix.isRedistributed()) {
233 redistributeMatrixAmg(const_cast<Matrix&>(matrix->getmat()),
234 const_cast<Matrix&>(matrix.getRedistributed().getmat()),
235 const_cast<PI&>(*info), const_cast<PI&>(info.getRedistributed()),
236 const_cast<Dune::RedistributeInformation<PI>&>(*redistInfo));
237 }
238#endif
239 }
240 }
241
245 template<class C>
246 void updateSolver(C& criterion, const Operator& /* matrix */, const PI& pinfo);
247
251 void update() override;
252
257 bool usesDirectCoarseLevelSolver() const;
258
259 private:
266 template<class C>
267 void createHierarchies(C& criterion, Operator& matrix,
268 const PI& pinfo)
269 {
270 //OPM_TIMEBLOCK(createHierarchies);
271 // create shared_ptr with empty deleter
272 std::shared_ptr< Operator > op( &matrix, []( Operator* ) {});
273 std::shared_ptr< PI > pifo( const_cast< PI* > (&pinfo), []( PI * ) {});
274 createHierarchies( criterion, op, pifo);
275 }
276
277 template<class C>
278 void createHierarchies(C& criterion, std::shared_ptr< Operator > matrix,
279 std::shared_ptr< PI > pinfo );
280
281 void setupCoarseSolver();
282
289 struct LevelContext
290 {
295 typename Hierarchy<Smoother,A>::Iterator smoother;
299 typename OperatorHierarchy::ParallelMatrixHierarchy::ConstIterator matrix;
303 typename ParallelInformationHierarchy::Iterator pinfo;
307 typename OperatorHierarchy::RedistributeInfoList::const_iterator redist;
311 typename OperatorHierarchy::AggregatesMapList::const_iterator aggregates;
315 typename Hierarchy<Domain,A>::Iterator lhs;
319 typename Hierarchy<Domain,A>::Iterator update;
323 typename Hierarchy<Range,A>::Iterator rhs;
327 std::size_t level;
328 };
329
330
335 void mgc(LevelContext& levelContext);
336
337 void additiveMgc();
338
345 void moveToFineLevel(LevelContext& levelContext,bool processedFineLevel);
346
351 bool moveToCoarseLevel(LevelContext& levelContext);
352
357 void initIteratorsWithFineLevel(LevelContext& levelContext);
358
360 std::shared_ptr<OperatorHierarchy> matrices_;
362 SmootherArgs smootherArgs_;
364 std::shared_ptr<Hierarchy<Smoother,A> > smoothers_;
366 std::shared_ptr<CoarseSolver> solver_;
368 std::shared_ptr< Hierarchy<Range,A> > rhs_;
370 std::shared_ptr< Hierarchy<Domain,A> > lhs_;
372 std::shared_ptr< Hierarchy<Domain,A> > update_;
374 using ScalarProduct = Dune::ScalarProduct<X>;
376 std::shared_ptr<ScalarProduct> scalarProduct_;
378 std::size_t gamma_;
380 std::size_t preSteps_;
382 std::size_t postSteps_;
383 bool buildHierarchy_;
384 bool additive;
385 bool coarsesolverconverged;
386 std::shared_ptr<Smoother> coarseSmoother_;
388 SolverCategory::Category category_;
390 std::size_t verbosity_;
391 };
392
393 template<class M, class X, class S, class PI, class A>
395 : matrices_(amg.matrices_), smootherArgs_(amg.smootherArgs_),
396 smoothers_(amg.smoothers_), solver_(amg.solver_),
397 rhs_(), lhs_(), update_(),
398 scalarProduct_(amg.scalarProduct_), gamma_(amg.gamma_),
399 preSteps_(amg.preSteps_), postSteps_(amg.postSteps_),
400 buildHierarchy_(amg.buildHierarchy_),
401 additive(amg.additive), coarsesolverconverged(amg.coarsesolverconverged),
402 coarseSmoother_(amg.coarseSmoother_),
403 category_(amg.category_),
404 verbosity_(amg.verbosity_)
405 {
406 if(amg.rhs_)
407 rhs_.reset( new Hierarchy<Range,A>(*amg.rhs_) );
408 if(amg.lhs_)
409 lhs_.reset( new Hierarchy<Domain,A>(*amg.lhs_) );
410 if(amg.update_)
411 update_.reset( new Hierarchy<Domain,A>(*amg.update_) );
412 }
413
414 template<class M, class X, class S, class PI, class A>
416 const SmootherArgs& smootherArgs,
417 const Parameters& parms)
418 : matrices_(stackobject_to_shared_ptr(matrices)), smootherArgs_(smootherArgs),
419 smoothers_(new Hierarchy<Smoother,A>), solver_(&coarseSolver),
420 rhs_(), lhs_(), update_(), scalarProduct_(0),
421 gamma_(parms.getGamma()), preSteps_(parms.getNoPreSmoothSteps()),
422 postSteps_(parms.getNoPostSmoothSteps()), buildHierarchy_(false),
423 additive(parms.getAdditive()), coarsesolverconverged(true),
424 coarseSmoother_(),
425// #warning should category be retrieved from matrices?
426 category_(SolverCategory::category(*smoothers_->coarsest())),
427 verbosity_(parms.debugLevel())
428 {
429 assert(matrices_->isBuilt());
430
431 // build the necessary smoother hierarchies
432 matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
433 }
434
435 template<class M, class X, class S, class PI, class A>
436 template<class C>
438 const C& criterion,
439 const SmootherArgs& smootherArgs,
440 const PI& pinfo)
441 : smootherArgs_(smootherArgs),
442 smoothers_(new Hierarchy<Smoother,A>), solver_(),
443 rhs_(), lhs_(), update_(), scalarProduct_(),
444 gamma_(criterion.getGamma()), preSteps_(criterion.getNoPreSmoothSteps()),
445 postSteps_(criterion.getNoPostSmoothSteps()), buildHierarchy_(true),
446 additive(criterion.getAdditive()), coarsesolverconverged(true),
447 coarseSmoother_(),
448 category_(SolverCategory::category(pinfo)),
449 verbosity_(criterion.debugLevel())
450 {
451 if(SolverCategory::category(matrix) != SolverCategory::category(pinfo))
452 DUNE_THROW(InvalidSolverCategory, "Matrix and Communication must have the same SolverCategory!");
453 createHierarchies(criterion, const_cast<Operator&>(matrix), pinfo);
454 }
455
456 template<class M, class X, class S, class PI, class A>
458 {
459 if(buildHierarchy_) {
460 if(solver_)
461 solver_.reset();
462 if(coarseSmoother_)
463 coarseSmoother_.reset();
464 }
465 }
466
467 template<class M, class X, class S, class PI, class A>
468 template<class C>
469 void AMGCPR<M,X,S,PI,A>::updateSolver(C& /* criterion */, const Operator& /* matrix */, const PI& /* pinfo */)
470 {
471 update();
472 }
473
474 template<class M, class X, class S, class PI, class A>
476 {
477 OPM_TIMEBLOCK(update);
478 Timer watch;
479 smoothers_.reset(new Hierarchy<Smoother,A>);
480 solver_.reset();
481 coarseSmoother_.reset();
482 scalarProduct_.reset();
483 buildHierarchy_= true;
484 coarsesolverconverged = true;
485 smoothers_.reset(new Hierarchy<Smoother,A>);
486 recalculateHierarchy();
487 matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
488 setupCoarseSolver();
489 if (verbosity_>0 && matrices_->parallelInformation().finest()->communicator().rank()==0) {
490 std::cout << "Recalculating galerkin and coarse smoothers "<< matrices_->maxlevels() << " levels "
491 << watch.elapsed() << " seconds." << std::endl;
492 }
493 }
494
495 template<class M, class X, class S, class PI, class A>
496 template<class C>
497 void AMGCPR<M,X,S,PI,A>::createHierarchies(C& criterion, std::shared_ptr< Operator > matrix,
498 std::shared_ptr< PI > pinfo )
499 {
500 OPM_TIMEBLOCK(createHierarchies);
501 Timer watch;
502 matrices_.reset(new OperatorHierarchy(matrix, pinfo));
503
504 matrices_->template build<NegateSet<typename PI::OwnerSet> >(criterion);
505
506 // build the necessary smoother hierarchies
507 matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
508 setupCoarseSolver();
509 if(verbosity_>0 && matrices_->parallelInformation().finest()->communicator().rank()==0)
510 std::cout<<"Building hierarchy of "<<matrices_->maxlevels()<<" levels "
511 <<"(inclusive coarse solver) took "<<watch.elapsed()<<" seconds."<<std::endl;
512 }
513
514 template<class M, class X, class S, class PI, class A>
515 void AMGCPR<M,X,S,PI,A>::setupCoarseSolver()
516 {
517 OPM_TIMEBLOCK(setupCoarseSolver);
518 // test whether we should solve on the coarse level. That is the case if we
519 // have that level and if there was a redistribution on this level then our
520 // communicator has to be valid (size()>0) as the smoother might try to communicate
521 // in the constructor.
522 if(buildHierarchy_ && matrices_->levels()==matrices_->maxlevels()
523 && ( ! matrices_->redistributeInformation().back().isSetup() ||
524 matrices_->parallelInformation().coarsest().getRedistributed().communicator().size() ) )
525 {
526 // We have the carsest level. Create the coarse Solver
527 SmootherArgs sargs(smootherArgs_);
528 sargs.iterations = 1;
529
530 typename ConstructionTraits<Smoother>::Arguments cargs;
531 cargs.setArgs(sargs);
532 if(matrices_->redistributeInformation().back().isSetup()) {
533 // Solve on the redistributed partitioning
534 cargs.setMatrix(matrices_->matrices().coarsest().getRedistributed().getmat());
535 cargs.setComm(matrices_->parallelInformation().coarsest().getRedistributed());
536 }else{
537 cargs.setMatrix(matrices_->matrices().coarsest()->getmat());
538 cargs.setComm(*matrices_->parallelInformation().coarsest());
539 }
540
541 coarseSmoother_ = ConstructionTraits<Smoother>::construct(cargs);
542 scalarProduct_ = createScalarProduct<X>(cargs.getComm(),category());
543
544 typedef DirectSolverSelector< typename M::matrix_type, X > SolverSelector;
545
546 // Use superlu if we are purely sequential or with only one processor on the coarsest level.
547 if( SolverSelector::isDirectSolver &&
548 (std::is_same<ParallelInformation,SequentialInformation>::value // sequential mode
549 || matrices_->parallelInformation().coarsest()->communicator().size()==1 //parallel mode and only one processor
550 || (matrices_->parallelInformation().coarsest().isRedistributed()
551 && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()==1
552 && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()>0) )
553 )
554 { // redistribute and 1 proc
555 if(matrices_->parallelInformation().coarsest().isRedistributed())
556 {
557 if(matrices_->matrices().coarsest().getRedistributed().getmat().N()>0)
558 {
559 // We are still participating on this level
560 solver_.reset(SolverSelector::create(matrices_->matrices().coarsest().getRedistributed().getmat(), false, false));
561 }
562 else
563 solver_.reset();
564 }
565 else
566 {
567 solver_.reset(SolverSelector::create(matrices_->matrices().coarsest()->getmat(), false, false));
568 }
569 if(verbosity_>0 && matrices_->parallelInformation().coarsest()->communicator().rank()==0)
570 std::cout<< "Using a direct coarse solver (" << SolverSelector::name() << ")" << std::endl;
571 }
572 else
573 {
574 if(matrices_->parallelInformation().coarsest().isRedistributed())
575 {
576 if(matrices_->matrices().coarsest().getRedistributed().getmat().N()>0)
577 // We are still participating on this level
578
579 // we have to allocate these types using the rebound allocator
580 // in order to ensure that we fulfill the alignement requirements
581 solver_.reset(new BiCGSTABSolver<X>(const_cast<M&>(matrices_->matrices().coarsest().getRedistributed()),
582 // Cast needed for Dune <=2.5
583 reinterpret_cast<typename
584 std::conditional<std::is_same<PI,SequentialInformation>::value,
585 Dune::SeqScalarProduct<X>,
586 Dune::OverlappingSchwarzScalarProduct<X,PI> >::type&>(*scalarProduct_),
587 *coarseSmoother_, 1E-2, 1000, 0));
588 else
589 solver_.reset();
590 }else
591 {
592 solver_.reset(new BiCGSTABSolver<X>(const_cast<M&>(*matrices_->matrices().coarsest()),
593 // Cast needed for Dune <=2.5
594 reinterpret_cast<typename
595 std::conditional<std::is_same<PI,SequentialInformation>::value,
596 Dune::SeqScalarProduct<X>,
597 Dune::OverlappingSchwarzScalarProduct<X,PI> >::type&>(*scalarProduct_),
598 *coarseSmoother_, 1E-2, 1000, 0));
599 // // we have to allocate these types using the rebound allocator
600 // // in order to ensure that we fulfill the alignement requirements
601 // using Alloc = typename A::template rebind<BiCGSTABSolver<X>>::other;
602 // Alloc alloc;
603 // auto p = alloc.allocate(1);
604 // alloc.construct(p,
605 // const_cast<M&>(*matrices_->matrices().coarsest()),
606 // *scalarProduct_,
607 // *coarseSmoother_, 1E-2, 1000, 0);
608 // solver_.reset(p,[](BiCGSTABSolver<X>* p){
609 // Alloc alloc;
610 // alloc.destroy(p);
611 // alloc.deallocate(p,1);
612 // });
613 }
614 }
615 }
616 }
617
618 template<class M, class X, class S, class PI, class A>
620 {
621 OPM_TIMEBLOCK(pre);
622 // Detect Matrix rows where all offdiagonal entries are
623 // zero and set x such that A_dd*x_d=b_d
624 // Thus users can be more careless when setting up their linear
625 // systems.
626 typedef typename M::matrix_type Matrix;
627 typedef typename Matrix::ConstRowIterator RowIter;
628 typedef typename Matrix::ConstColIterator ColIter;
629 typedef typename Matrix::block_type Block;
630 Block zero;
631 zero=typename Matrix::field_type();
632
633 const Matrix& mat=matrices_->matrices().finest()->getmat();
634 for(RowIter row=mat.begin(); row!=mat.end(); ++row) {
635 bool isDirichlet = true;
636 bool hasDiagonal = false;
637 Block diagonal;
638 for(ColIter col=row->begin(); col!=row->end(); ++col) {
639 if(row.index()==col.index()) {
640 diagonal = *col;
641 hasDiagonal = false;
642 }else{
643 if(*col!=zero)
644 isDirichlet = false;
645 }
646 }
647 if(isDirichlet && hasDiagonal)
648 diagonal.solve(x[row.index()], b[row.index()]);
649 }
650
651 if(smoothers_->levels()>0)
652 smoothers_->finest()->pre(x,b);
653 else
654 // No smoother to make x consistent! Do it by hand
655 matrices_->parallelInformation().coarsest()->copyOwnerToAll(x,x);
656
657
658 typedef std::shared_ptr< Range > RangePtr ;
659 typedef std::shared_ptr< Domain > DomainPtr;
660
661 // Hierarchy takes ownership of pointers
662 RangePtr copy( new Range(b) );
663 rhs_.reset( new Hierarchy<Range,A>(copy) );
664 DomainPtr dcopy( new Domain(x) );
665 lhs_.reset( new Hierarchy<Domain,A>(dcopy) );
666 DomainPtr dcopy2( new Domain(x) );
667 update_.reset( new Hierarchy<Domain,A>(dcopy2) );
668
669 matrices_->coarsenVector(*rhs_);
670 matrices_->coarsenVector(*lhs_);
671 matrices_->coarsenVector(*update_);
672
673 // Preprocess all smoothers
674 typedef typename Hierarchy<Smoother,A>::Iterator Iterator;
675 typedef typename Hierarchy<Range,A>::Iterator RIterator;
676 typedef typename Hierarchy<Domain,A>::Iterator DIterator;
677 Iterator coarsest = smoothers_->coarsest();
678 Iterator smoother = smoothers_->finest();
679 RIterator rhs = rhs_->finest();
680 DIterator lhs = lhs_->finest();
681 if(smoothers_->levels()>0) {
682
683 assert(lhs_->levels()==rhs_->levels());
684 assert(smoothers_->levels()==lhs_->levels() || matrices_->levels()==matrices_->maxlevels());
685 assert(smoothers_->levels()+1==lhs_->levels() || matrices_->levels()<matrices_->maxlevels());
686
687 if(smoother!=coarsest)
688 for(++smoother, ++lhs, ++rhs; smoother != coarsest; ++smoother, ++lhs, ++rhs)
689 smoother->pre(*lhs,*rhs);
690 smoother->pre(*lhs,*rhs);
691 }
692
693
694 // The preconditioner might change x and b. So we have to
695 // copy the changes to the original vectors.
696 x = *lhs_->finest();
697 b = *rhs_->finest();
698
699 }
700 template<class M, class X, class S, class PI, class A>
702 {
703 return matrices_->levels();
704 }
705 template<class M, class X, class S, class PI, class A>
707 {
708 return matrices_->maxlevels();
709 }
710
712 template<class M, class X, class S, class PI, class A>
714 {
715 OPM_TIMEBLOCK(apply);
716 LevelContext levelContext;
717
718 if(additive) {
719 *(rhs_->finest())=d;
720 additiveMgc();
721 v=*lhs_->finest();
722 }else{
723 // Init all iterators for the current level
724 initIteratorsWithFineLevel(levelContext);
725
726
727 *levelContext.lhs = v;
728 *levelContext.rhs = d;
729 *levelContext.update=0;
730 levelContext.level=0;
731
732 mgc(levelContext);
733
734 if(postSteps_==0||matrices_->maxlevels()==1)
735 levelContext.pinfo->copyOwnerToAll(*levelContext.update, *levelContext.update);
736
737 v=*levelContext.update;
738 }
739
740 }
741
742 template<class M, class X, class S, class PI, class A>
743 void AMGCPR<M,X,S,PI,A>::initIteratorsWithFineLevel(LevelContext& levelContext)
744 {
745 OPM_TIMEBLOCK(initIteratorsWithFineLevel);
746 levelContext.smoother = smoothers_->finest();
747 levelContext.matrix = matrices_->matrices().finest();
748 levelContext.pinfo = matrices_->parallelInformation().finest();
749 levelContext.redist =
750 matrices_->redistributeInformation().begin();
751 levelContext.aggregates = matrices_->aggregatesMaps().begin();
752 levelContext.lhs = lhs_->finest();
753 levelContext.update = update_->finest();
754 levelContext.rhs = rhs_->finest();
755 }
756
757 template<class M, class X, class S, class PI, class A>
758 bool AMGCPR<M,X,S,PI,A>
759 ::moveToCoarseLevel(LevelContext& levelContext)
760 {
761 OPM_TIMEBLOCK(moveToCoarseLevel);
762 bool processNextLevel=true;
763
764 if(levelContext.redist->isSetup()) {
765 levelContext.redist->redistribute(static_cast<const Range&>(*levelContext.rhs),
766 levelContext.rhs.getRedistributed());
767 processNextLevel = levelContext.rhs.getRedistributed().size()>0;
768 if(processNextLevel) {
769 //restrict defect to coarse level right hand side.
770 typename Hierarchy<Range,A>::Iterator fineRhs = levelContext.rhs++;
771 ++levelContext.pinfo;
772 Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
773 ::restrictVector(*(*levelContext.aggregates), *levelContext.rhs,
774 static_cast<const Range&>(fineRhs.getRedistributed()),
775 *levelContext.pinfo);
776 }
777 }else{
778 //restrict defect to coarse level right hand side.
779 typename Hierarchy<Range,A>::Iterator fineRhs = levelContext.rhs++;
780 ++levelContext.pinfo;
781 Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
782 ::restrictVector(*(*levelContext.aggregates),
783 *levelContext.rhs, static_cast<const Range&>(*fineRhs),
784 *levelContext.pinfo);
785 }
786
787 if(processNextLevel) {
788 // prepare coarse system
789 ++levelContext.lhs;
790 ++levelContext.update;
791 ++levelContext.matrix;
792 ++levelContext.level;
793 ++levelContext.redist;
794
795 if(levelContext.matrix != matrices_->matrices().coarsest() || matrices_->levels()<matrices_->maxlevels()) {
796 // next level is not the globally coarsest one
797 ++levelContext.smoother;
798 ++levelContext.aggregates;
799 }
800 // prepare the update on the next level
801 *levelContext.update=0;
802 }
803 return processNextLevel;
804 }
805
806 template<class M, class X, class S, class PI, class A>
807 void AMGCPR<M,X,S,PI,A>
808 ::moveToFineLevel(LevelContext& levelContext, bool processNextLevel)
809 {
810 OPM_TIMEBLOCK(moveToFineLevel);
811 if(processNextLevel) {
812 if(levelContext.matrix != matrices_->matrices().coarsest() || matrices_->levels()<matrices_->maxlevels()) {
813 // previous level is not the globally coarsest one
814 --levelContext.smoother;
815 --levelContext.aggregates;
816 }
817 --levelContext.redist;
818 --levelContext.level;
819 //prolongate and add the correction (update is in coarse left hand side)
820 --levelContext.matrix;
821
822 //typename Hierarchy<Domain,A>::Iterator coarseLhs = lhs--;
823 --levelContext.lhs;
824 --levelContext.pinfo;
825 }
826 if(levelContext.redist->isSetup()) {
827 // Need to redistribute during prolongateVector
828 levelContext.lhs.getRedistributed()=0;
829 Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
830 ::prolongateVector(*(*levelContext.aggregates), *levelContext.update, *levelContext.lhs,
831 levelContext.lhs.getRedistributed(),
832 matrices_->getProlongationDampingFactor(),
833 *levelContext.pinfo, *levelContext.redist);
834 }else{
835 *levelContext.lhs=0;
836 Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
837 ::prolongateVector(*(*levelContext.aggregates), *levelContext.update, *levelContext.lhs,
838 matrices_->getProlongationDampingFactor(),
839 *levelContext.pinfo);
840 }
841
842
843 if(processNextLevel) {
844 --levelContext.update;
845 --levelContext.rhs;
846 }
847
848 *levelContext.update += *levelContext.lhs;
849 }
850
851 template<class M, class X, class S, class PI, class A>
853 {
854 return IsDirectSolver< CoarseSolver>::value;
855 }
856
857 template<class M, class X, class S, class PI, class A>
858 void AMGCPR<M,X,S,PI,A>::mgc(LevelContext& levelContext){
859 //OPM_TIMEBLOCK(mgc);
860 if(levelContext.matrix == matrices_->matrices().coarsest() && levels()==maxlevels()) {
861 // Solve directly
863 res.converged=true; // If we do not compute this flag will not get updated
864 if(levelContext.redist->isSetup()) {
865 levelContext.redist->redistribute(*levelContext.rhs, levelContext.rhs.getRedistributed());
866 if(levelContext.rhs.getRedistributed().size()>0) {
867 // We are still participating in the computation
868 levelContext.pinfo.getRedistributed().copyOwnerToAll(levelContext.rhs.getRedistributed(),
869 levelContext.rhs.getRedistributed());
870 solver_->apply(levelContext.update.getRedistributed(),
871 levelContext.rhs.getRedistributed(), res);
872 }
873 levelContext.redist->redistributeBackward(*levelContext.update, levelContext.update.getRedistributed());
874 levelContext.pinfo->copyOwnerToAll(*levelContext.update, *levelContext.update);
875 }else{
876 levelContext.pinfo->copyOwnerToAll(*levelContext.rhs, *levelContext.rhs);
877 solver_->apply(*levelContext.update, *levelContext.rhs, res);
878 }
879
880 if (!res.converged)
881 coarsesolverconverged = false;
882 }else{
883 // presmoothing
884 presmooth(levelContext, preSteps_);
885
886#ifndef DUNE_AMG_NO_COARSEGRIDCORRECTION
887 bool processNextLevel = moveToCoarseLevel(levelContext);
888
889 if(processNextLevel) {
890 // next level
891 for(std::size_t i=0; i<gamma_; i++)
892 mgc(levelContext);
893 }
894
895 moveToFineLevel(levelContext, processNextLevel);
896#else
897 *lhs=0;
898#endif
899
900 if(levelContext.matrix == matrices_->matrices().finest()) {
901 coarsesolverconverged = matrices_->parallelInformation().finest()->communicator().prod(coarsesolverconverged);
902 if(!coarsesolverconverged){
903 //DUNE_THROW(MathError, "Coarse solver did not converge");
904 }
905 }
906 // postsmoothing
907 postsmooth(levelContext, postSteps_);
908
909 }
910 }
911
912 template<class M, class X, class S, class PI, class A>
913 void AMGCPR<M,X,S,PI,A>::additiveMgc(){
914 OPM_TIMEBLOCK(additiveMgc);
915 // restrict residual to all levels
916 typename ParallelInformationHierarchy::Iterator pinfo=matrices_->parallelInformation().finest();
917 typename Hierarchy<Range,A>::Iterator rhs=rhs_->finest();
918 typename Hierarchy<Domain,A>::Iterator lhs = lhs_->finest();
919 typename OperatorHierarchy::AggregatesMapList::const_iterator aggregates=matrices_->aggregatesMaps().begin();
920
921 for(typename Hierarchy<Range,A>::Iterator fineRhs=rhs++; fineRhs != rhs_->coarsest(); fineRhs=rhs++, ++aggregates) {
922 ++pinfo;
923 Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
924 ::restrictVector(*(*aggregates), *rhs, static_cast<const Range&>(*fineRhs), *pinfo);
925 }
926
927 // pinfo is invalid, set to coarsest level
928 //pinfo = matrices_->parallelInformation().coarsest
929 // calculate correction for all levels
930 lhs = lhs_->finest();
931 typename Hierarchy<Smoother,A>::Iterator smoother = smoothers_->finest();
932
933 for(rhs=rhs_->finest(); rhs != rhs_->coarsest(); ++lhs, ++rhs, ++smoother) {
934 // presmoothing
935 *lhs=0;
936 smoother->apply(*lhs, *rhs);
937 }
938
939 // Coarse level solve
940#ifndef DUNE_AMG_NO_COARSEGRIDCORRECTION
942 pinfo->copyOwnerToAll(*rhs, *rhs);
943 solver_->apply(*lhs, *rhs, res);
944
945 if(!res.converged)
946 DUNE_THROW(MathError, "Coarse solver did not converge");
947#else
948 *lhs=0;
949#endif
950 // Prologate and add up corrections from all levels
951 --pinfo;
952 --aggregates;
953
954 for(typename Hierarchy<Domain,A>::Iterator coarseLhs = lhs--; coarseLhs != lhs_->finest(); coarseLhs = lhs--, --aggregates, --pinfo) {
955 Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
956 ::prolongateVector(*(*aggregates), *coarseLhs, *lhs, 1.0, *pinfo);
957 }
958 }
959
960
962 template<class M, class X, class S, class PI, class A>
963 void AMGCPR<M,X,S,PI,A>::post([[maybe_unused]] Domain& x)
964 {
965 OPM_TIMEBLOCK(post);
966 // Postprocess all smoothers
967 typedef typename Hierarchy<Smoother,A>::Iterator Iterator;
968 typedef typename Hierarchy<Domain,A>::Iterator DIterator;
969 Iterator coarsest = smoothers_->coarsest();
970 Iterator smoother = smoothers_->finest();
971 DIterator lhs = lhs_->finest();
972 if(smoothers_->levels()>0) {
973 if(smoother != coarsest || matrices_->levels()<matrices_->maxlevels())
974 smoother->post(*lhs);
975 if(smoother!=coarsest)
976 for(++smoother, ++lhs; smoother != coarsest; ++smoother, ++lhs)
977 smoother->post(*lhs);
978 smoother->post(*lhs);
979 }
980 //delete &(*lhs_->finest());
981 lhs_.reset();
982 //delete &(*update_->finest());
983 update_.reset();
984 //delete &(*rhs_->finest());
985 rhs_.reset();
986 }
987
988 template<class M, class X, class S, class PI, class A>
989 template<class A1>
990 void AMGCPR<M,X,S,PI,A>::getCoarsestAggregateNumbers(std::vector<std::size_t,A1>& cont)
991 {
992 matrices_->getCoarsestAggregatesOnFinest(cont);
993 }
994
995 } // end namespace Amg
996} // end namespace Dune
997
998#endif
Parallel algebraic multigrid based on agglomeration.
Definition: amgcpr.hh:88
Definition: amgcpr.hh:70
Definition: amgcpr.hh:73
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:32
M Operator
The matrix operator type.
Definition: amgcpr.hh:96
Hierarchy< Smoother, A >::Iterator smoother
The iterator over the smoothers.
Definition: amgcpr.hh:295
void post(Domain &x) override
Definition: amgcpr.hh:963
AMGCPR(const OperatorHierarchy &matrices, CoarseSolver &coarseSolver, const SmootherArgs &smootherArgs, const Parameters &parms)
Construct a new amg with a specific coarse solver.
Definition: amgcpr.hh:415
Hierarchy< Domain, A >::Iterator update
The iterator over the updates.
Definition: amgcpr.hh:319
Hierarchy< Range, A >::Iterator rhs
The iterator over the right hand sided.
Definition: amgcpr.hh:323
MatrixHierarchy< M, ParallelInformation, A > OperatorHierarchy
The operator hierarchy type.
Definition: amgcpr.hh:105
ParallelInformationHierarchy::Iterator pinfo
The iterator over the parallel information.
Definition: amgcpr.hh:303
OperatorHierarchy::ParallelMatrixHierarchy::ConstIterator matrix
The iterator over the matrices.
Definition: amgcpr.hh:299
void getCoarsestAggregateNumbers(std::vector< std::size_t, A1 > &cont)
Get the aggregate number of each unknown on the coarsest level.
Definition: amgcpr.hh:990
OperatorHierarchy::ParallelInformationHierarchy ParallelInformationHierarchy
The parallal data distribution hierarchy type.
Definition: amgcpr.hh:107
~AMGCPR()
Definition: amgcpr.hh:457
void recalculateHierarchy()
Recalculate the matrix hierarchy.
Definition: amgcpr.hh:199
SmootherTraits< Smoother >::Arguments SmootherArgs
The argument type for the construction of the smoother.
Definition: amgcpr.hh:123
void apply(Domain &v, const Range &d) override
Definition: amgcpr.hh:713
X Range
The range type.
Definition: amgcpr.hh:112
void pre(Domain &x, Range &b) override
Definition: amgcpr.hh:619
X Domain
The domain type.
Definition: amgcpr.hh:110
void update() override
Update the coarse solver and the hierarchies.
Definition: amgcpr.hh:475
std::size_t maxlevels()
Definition: amgcpr.hh:706
S Smoother
The type of the smoother.
Definition: amgcpr.hh:120
void updateSolver(C &criterion, const Operator &, const PI &pinfo)
Update the coarse solver and the hierarchies.
Definition: amgcpr.hh:469
bool hasPerfectUpdate() const override
Definition: amgcpr.hh:172
OperatorHierarchy::AggregatesMapList::const_iterator aggregates
The iterator over the aggregates maps.
Definition: amgcpr.hh:311
PI ParallelInformation
The type of the parallel information. Either OwnerOverlapCommunication or another type describing the...
Definition: amgcpr.hh:103
InverseOperator< X, X > CoarseSolver
the type of the coarse solver.
Definition: amgcpr.hh:114
std::size_t level
The level index.
Definition: amgcpr.hh:327
Hierarchy< Domain, A >::Iterator lhs
The iterator over the left hand side.
Definition: amgcpr.hh:315
bool usesDirectCoarseLevelSolver() const
Check whether the coarse solver used is a direct solver.
Definition: amgcpr.hh:852
Smoother SmootherType
Definition: amgcpr.hh:291
OperatorHierarchy::RedistributeInfoList::const_iterator redist
The iterator over the redistribution information.
Definition: amgcpr.hh:307
SolverCategory::Category category() const override
Category of the preconditioner (see SolverCategory::Category)
Definition: amgcpr.hh:167
std::size_t levels()
Definition: amgcpr.hh:701
void redistributeMatrixAmg(M &, M &, SequentialInformation &, SequentialInformation &, T &)
Definition: amgcpr.hh:35
Definition: fvbaseprimaryvariables.hh:141
Dune::InverseOperatorResult InverseOperatorResult
Definition: BdaBridge.hpp:32