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
162 {
163 dirichletPresolve_ = on;
164 }
165
167 void pre(Domain& x, Range& b) override;
168
170 void apply(Domain& v, const Range& d) override;
171
173 SolverCategory::Category category() const override
174 {
175 return category_;
176 }
177
178 bool hasPerfectUpdate() const override
179 {
180 return false;
181 }
182
184 void post(Domain& x) override;
185
190 template<class A1>
191 void getCoarsestAggregateNumbers(std::vector<std::size_t,A1>& cont);
192
193 std::size_t levels();
194
195 std::size_t maxlevels();
196
206 {
207 OPM_TIMEBLOCK(recalculateHierarch);
208 auto copyFlags = NegateSet<typename PI::OwnerSet>();
209 const auto& matrices = matrices_->matrices();
210 const auto& aggregatesMapHierarchy = matrices_->aggregatesMaps();
211 const auto& infoHierarchy = matrices_->parallelInformation();
212 const auto& redistInfoHierarchy = matrices_->redistributeInformation();
213 BaseGalerkinProduct productBuilder;
214 auto aggregatesMap = aggregatesMapHierarchy.begin();
215 auto info = infoHierarchy.finest();
216 auto redistInfo = redistInfoHierarchy.begin();
217 auto matrix = matrices.finest();
218 auto coarsestMatrix = matrices.coarsest();
219
220 using Matrix = typename M::matrix_type;
221
222#if HAVE_MPI
223 if(matrix.isRedistributed()) {
224 redistributeMatrixAmg(const_cast<Matrix&>(matrix->getmat()),
225 const_cast<Matrix&>(matrix.getRedistributed().getmat()),
226 const_cast<PI&>(*info), const_cast<PI&>(info.getRedistributed()),
227 const_cast<Dune::RedistributeInformation<PI>&>(*redistInfo));
228 }
229#endif
230
231 for(; matrix!=coarsestMatrix; ++aggregatesMap) {
232 const Matrix& fine = (matrix.isRedistributed() ? matrix.getRedistributed() : *matrix).getmat();
233 ++matrix;
234 ++info;
235 ++redistInfo;
236 productBuilder.calculate(fine, *(*aggregatesMap), const_cast<Matrix&>(matrix->getmat()), *info, copyFlags);
237#if HAVE_MPI
238 if(matrix.isRedistributed()) {
239 redistributeMatrixAmg(const_cast<Matrix&>(matrix->getmat()),
240 const_cast<Matrix&>(matrix.getRedistributed().getmat()),
241 const_cast<PI&>(*info), const_cast<PI&>(info.getRedistributed()),
242 const_cast<Dune::RedistributeInformation<PI>&>(*redistInfo));
243 }
244#endif
245 }
246 }
247
251 template<class C>
252 void updateSolver(C& criterion, const Operator& /* matrix */, const PI& pinfo);
253
257 void update() override;
258
263 bool usesDirectCoarseLevelSolver() const;
264
265 private:
272 template<class C>
273 void createHierarchies(C& criterion, Operator& matrix,
274 const PI& pinfo)
275 {
276 //OPM_TIMEBLOCK(createHierarchies);
277 // create shared_ptr with empty deleter
278 std::shared_ptr< Operator > op( &matrix, []( Operator* ) {});
279 std::shared_ptr< PI > pifo( const_cast< PI* > (&pinfo), []( PI * ) {});
280 createHierarchies( criterion, op, pifo);
281 }
282
283 template<class C>
284 void createHierarchies(C& criterion, std::shared_ptr< Operator > matrix,
285 std::shared_ptr< PI > pinfo );
286
287 void setupCoarseSolver();
288
295 struct LevelContext
296 {
301 typename Hierarchy<Smoother,A>::Iterator smoother;
305 typename OperatorHierarchy::ParallelMatrixHierarchy::ConstIterator matrix;
309 typename ParallelInformationHierarchy::Iterator pinfo;
313 typename OperatorHierarchy::RedistributeInfoList::const_iterator redist;
317 typename OperatorHierarchy::AggregatesMapList::const_iterator aggregates;
321 typename Hierarchy<Domain,A>::Iterator lhs;
325 typename Hierarchy<Domain,A>::Iterator update;
329 typename Hierarchy<Range,A>::Iterator rhs;
333 std::size_t level;
334 };
335
336
341 void mgc(LevelContext& levelContext);
342
343 void additiveMgc();
344
351 void moveToFineLevel(LevelContext& levelContext,bool processedFineLevel);
352
357 bool moveToCoarseLevel(LevelContext& levelContext);
358
363 void initIteratorsWithFineLevel(LevelContext& levelContext);
364
366 std::shared_ptr<OperatorHierarchy> matrices_;
368 SmootherArgs smootherArgs_;
370 std::shared_ptr<Hierarchy<Smoother,A> > smoothers_;
372 std::shared_ptr<CoarseSolver> solver_;
374 std::shared_ptr< Hierarchy<Range,A> > rhs_;
376 std::shared_ptr< Hierarchy<Domain,A> > lhs_;
378 std::shared_ptr< Hierarchy<Domain,A> > update_;
380 using ScalarProduct = Dune::ScalarProduct<X>;
382 std::shared_ptr<ScalarProduct> scalarProduct_;
384 std::size_t gamma_;
386 std::size_t preSteps_;
388 std::size_t postSteps_;
389 bool buildHierarchy_;
390 bool additive;
391 bool coarsesolverconverged;
392 std::shared_ptr<Smoother> coarseSmoother_;
394 SolverCategory::Category category_;
396 std::size_t verbosity_;
397 bool dirichletPresolve_ = false;
398 };
399
400 template<class M, class X, class S, class PI, class A>
402 : matrices_(amg.matrices_), smootherArgs_(amg.smootherArgs_),
403 smoothers_(amg.smoothers_), solver_(amg.solver_),
404 rhs_(), lhs_(), update_(),
405 scalarProduct_(amg.scalarProduct_), gamma_(amg.gamma_),
406 preSteps_(amg.preSteps_), postSteps_(amg.postSteps_),
407 buildHierarchy_(amg.buildHierarchy_),
408 additive(amg.additive), coarsesolverconverged(amg.coarsesolverconverged),
409 coarseSmoother_(amg.coarseSmoother_),
410 category_(amg.category_),
411 verbosity_(amg.verbosity_),
412 dirichletPresolve_(amg.dirichletPresolve_)
413 {
414 if(amg.rhs_)
415 rhs_.reset( new Hierarchy<Range,A>(*amg.rhs_) );
416 if(amg.lhs_)
417 lhs_.reset( new Hierarchy<Domain,A>(*amg.lhs_) );
418 if(amg.update_)
419 update_.reset( new Hierarchy<Domain,A>(*amg.update_) );
420 }
421
422 template<class M, class X, class S, class PI, class A>
424 const SmootherArgs& smootherArgs,
425 const Parameters& parms)
426 : matrices_(stackobject_to_shared_ptr(matrices)), smootherArgs_(smootherArgs),
427 smoothers_(new Hierarchy<Smoother,A>), solver_(&coarseSolver),
428 rhs_(), lhs_(), update_(), scalarProduct_(0),
429 gamma_(parms.getGamma()), preSteps_(parms.getNoPreSmoothSteps()),
430 postSteps_(parms.getNoPostSmoothSteps()), buildHierarchy_(false),
431 additive(parms.getAdditive()), coarsesolverconverged(true),
432 coarseSmoother_(),
433// #warning should category be retrieved from matrices?
434 category_(SolverCategory::category(*smoothers_->coarsest())),
435 verbosity_(parms.debugLevel())
436 {
437 assert(matrices_->isBuilt());
438
439 // build the necessary smoother hierarchies
440 matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
441 }
442
443 template<class M, class X, class S, class PI, class A>
444 template<class C>
446 const C& criterion,
447 const SmootherArgs& smootherArgs,
448 const PI& pinfo)
449 : smootherArgs_(smootherArgs),
450 smoothers_(new Hierarchy<Smoother,A>), solver_(),
451 rhs_(), lhs_(), update_(), scalarProduct_(),
452 gamma_(criterion.getGamma()), preSteps_(criterion.getNoPreSmoothSteps()),
453 postSteps_(criterion.getNoPostSmoothSteps()), buildHierarchy_(true),
454 additive(criterion.getAdditive()), coarsesolverconverged(true),
455 coarseSmoother_(),
456 category_(SolverCategory::category(pinfo)),
457 verbosity_(criterion.debugLevel())
458 {
459 if(SolverCategory::category(matrix) != SolverCategory::category(pinfo))
460 DUNE_THROW(InvalidSolverCategory, "Matrix and Communication must have the same SolverCategory!");
461 createHierarchies(criterion, const_cast<Operator&>(matrix), pinfo);
462 }
463
464 template<class M, class X, class S, class PI, class A>
466 {
467 if(buildHierarchy_) {
468 if(solver_)
469 solver_.reset();
470 if(coarseSmoother_)
471 coarseSmoother_.reset();
472 }
473 }
474
475 template<class M, class X, class S, class PI, class A>
476 template<class C>
477 void AMGCPR<M,X,S,PI,A>::updateSolver(C& /* criterion */, const Operator& /* matrix */, const PI& /* pinfo */)
478 {
479 update();
480 }
481
482 template<class M, class X, class S, class PI, class A>
484 {
485 OPM_TIMEBLOCK(update);
486 Timer watch;
487 smoothers_.reset(new Hierarchy<Smoother,A>);
488 solver_.reset();
489 coarseSmoother_.reset();
490 scalarProduct_.reset();
491 buildHierarchy_= true;
492 coarsesolverconverged = true;
493 smoothers_.reset(new Hierarchy<Smoother,A>);
494 recalculateHierarchy();
495 matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
496 setupCoarseSolver();
497 if (verbosity_>0 && matrices_->parallelInformation().finest()->communicator().rank()==0) {
498 std::cout << "Recalculating galerkin and coarse smoothers "<< matrices_->maxlevels() << " levels "
499 << watch.elapsed() << " seconds." << std::endl;
500 }
501 }
502
503 template<class M, class X, class S, class PI, class A>
504 template<class C>
505 void AMGCPR<M,X,S,PI,A>::createHierarchies(C& criterion, std::shared_ptr< Operator > matrix,
506 std::shared_ptr< PI > pinfo )
507 {
508 OPM_TIMEBLOCK(createHierarchies);
509 Timer watch;
510 matrices_.reset(new OperatorHierarchy(matrix, pinfo));
511
512 matrices_->template build<NegateSet<typename PI::OwnerSet> >(criterion);
513
514 // build the necessary smoother hierarchies
515 matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
516 setupCoarseSolver();
517 if(verbosity_>0 && matrices_->parallelInformation().finest()->communicator().rank()==0)
518 std::cout<<"Building hierarchy of "<<matrices_->maxlevels()<<" levels "
519 <<"(inclusive coarse solver) took "<<watch.elapsed()<<" seconds."<<std::endl;
520 }
521
522 template<class M, class X, class S, class PI, class A>
523 void AMGCPR<M,X,S,PI,A>::setupCoarseSolver()
524 {
525 OPM_TIMEBLOCK(setupCoarseSolver);
526 // test whether we should solve on the coarse level. That is the case if we
527 // have that level and if there was a redistribution on this level then our
528 // communicator has to be valid (size()>0) as the smoother might try to communicate
529 // in the constructor.
530 if(buildHierarchy_ && matrices_->levels()==matrices_->maxlevels()
531 && ( ! matrices_->redistributeInformation().back().isSetup() ||
532 matrices_->parallelInformation().coarsest().getRedistributed().communicator().size() ) )
533 {
534 // We have the carsest level. Create the coarse Solver
535 SmootherArgs sargs(smootherArgs_);
536 sargs.iterations = 1;
537
538 typename ConstructionTraits<Smoother>::Arguments cargs;
539 cargs.setArgs(sargs);
540 if(matrices_->redistributeInformation().back().isSetup()) {
541 // Solve on the redistributed partitioning
542 cargs.setMatrix(matrices_->matrices().coarsest().getRedistributed().getmat());
543 cargs.setComm(matrices_->parallelInformation().coarsest().getRedistributed());
544 }else{
545 cargs.setMatrix(matrices_->matrices().coarsest()->getmat());
546 cargs.setComm(*matrices_->parallelInformation().coarsest());
547 }
548
549 coarseSmoother_ = ConstructionTraits<Smoother>::construct(cargs);
550 scalarProduct_ = createScalarProduct<X>(cargs.getComm(),category());
551
552 typedef DirectSolverSelector< typename M::matrix_type, X > SolverSelector;
553
554 // Use superlu if we are purely sequential or with only one processor on the coarsest level.
555 if( SolverSelector::isDirectSolver &&
556 (std::is_same<ParallelInformation,SequentialInformation>::value // sequential mode
557 || matrices_->parallelInformation().coarsest()->communicator().size()==1 //parallel mode and only one processor
558 || (matrices_->parallelInformation().coarsest().isRedistributed()
559 && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()==1
560 && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()>0) )
561 )
562 { // redistribute and 1 proc
563 if(matrices_->parallelInformation().coarsest().isRedistributed())
564 {
565 if(matrices_->matrices().coarsest().getRedistributed().getmat().N()>0)
566 {
567 // We are still participating on this level
568 solver_.reset(SolverSelector::create(matrices_->matrices().coarsest().getRedistributed().getmat(), false, false));
569 }
570 else
571 solver_.reset();
572 }
573 else
574 {
575 solver_.reset(SolverSelector::create(matrices_->matrices().coarsest()->getmat(), false, false));
576 }
577 if(verbosity_>0 && matrices_->parallelInformation().coarsest()->communicator().rank()==0)
578 std::cout<< "Using a direct coarse solver (" << SolverSelector::name() << ")" << std::endl;
579 }
580 else
581 {
582 if(matrices_->parallelInformation().coarsest().isRedistributed())
583 {
584 if(matrices_->matrices().coarsest().getRedistributed().getmat().N()>0)
585 // We are still participating on this level
586
587 // we have to allocate these types using the rebound allocator
588 // in order to ensure that we fulfill the alignement requirements
589 solver_.reset(new BiCGSTABSolver<X>(const_cast<M&>(matrices_->matrices().coarsest().getRedistributed()),
590 // Cast needed for Dune <=2.5
591 reinterpret_cast<typename
592 std::conditional<std::is_same<PI,SequentialInformation>::value,
593 Dune::SeqScalarProduct<X>,
594 Dune::OverlappingSchwarzScalarProduct<X,PI> >::type&>(*scalarProduct_),
595 *coarseSmoother_, 1E-2, 1000, 0));
596 else
597 solver_.reset();
598 }else
599 {
600 solver_.reset(new BiCGSTABSolver<X>(const_cast<M&>(*matrices_->matrices().coarsest()),
601 // Cast needed for Dune <=2.5
602 reinterpret_cast<typename
603 std::conditional<std::is_same<PI,SequentialInformation>::value,
604 Dune::SeqScalarProduct<X>,
605 Dune::OverlappingSchwarzScalarProduct<X,PI> >::type&>(*scalarProduct_),
606 *coarseSmoother_, 1E-2, 1000, 0));
607 // // we have to allocate these types using the rebound allocator
608 // // in order to ensure that we fulfill the alignement requirements
609 // using Alloc = typename A::template rebind<BiCGSTABSolver<X>>::other;
610 // Alloc alloc;
611 // auto p = alloc.allocate(1);
612 // alloc.construct(p,
613 // const_cast<M&>(*matrices_->matrices().coarsest()),
614 // *scalarProduct_,
615 // *coarseSmoother_, 1E-2, 1000, 0);
616 // solver_.reset(p,[](BiCGSTABSolver<X>* p){
617 // Alloc alloc;
618 // alloc.destroy(p);
619 // alloc.deallocate(p,1);
620 // });
621 }
622 }
623 }
624 }
625
626 template<class M, class X, class S, class PI, class A>
628 {
629 OPM_TIMEBLOCK(pre);
630 if (dirichletPresolve_) {
631 // Detect Matrix rows where all offdiagonal entries are
632 // zero and set x such that A_dd*x_d=b_d
633 // Thus users can be more careless when setting up their linear
634 // systems.
635 typedef typename M::matrix_type Matrix;
636 typedef typename Matrix::ConstRowIterator RowIter;
637 typedef typename Matrix::ConstColIterator ColIter;
638 typedef typename Matrix::block_type Block;
639 Block zero;
640 zero=typename Matrix::field_type();
641
642 const Matrix& mat=matrices_->matrices().finest()->getmat();
643 for(RowIter row=mat.begin(); row!=mat.end(); ++row) {
644 bool isDirichlet = true;
645 bool hasDiagonal = false;
646 Block diagonal;
647 for(ColIter col=row->begin(); col!=row->end(); ++col) {
648 if(row.index()==col.index()) {
649 if (*col != zero) {
650 diagonal = *col;
651 hasDiagonal = true;
652 } else {
653 break;
654 }
655 }else{
656 if (*col != zero) {
657 isDirichlet = false;
658 break;
659 }
660 }
661 }
662 if(isDirichlet && hasDiagonal)
663 diagonal.solve(x[row.index()], b[row.index()]);
664 }
665 // The rows above are solved per rank.
666 matrices_->parallelInformation().finest()->copyOwnerToAll(x,x);
667 }
668
669 if(smoothers_->levels()>0)
670 smoothers_->finest()->pre(x,b);
671
672
673 typedef std::shared_ptr< Range > RangePtr ;
674 typedef std::shared_ptr< Domain > DomainPtr;
675
676 // Hierarchy takes ownership of pointers
677 RangePtr copy( new Range(b) );
678 rhs_.reset( new Hierarchy<Range,A>(copy) );
679 DomainPtr dcopy( new Domain(x) );
680 lhs_.reset( new Hierarchy<Domain,A>(dcopy) );
681 DomainPtr dcopy2( new Domain(x) );
682 update_.reset( new Hierarchy<Domain,A>(dcopy2) );
683
684 matrices_->coarsenVector(*rhs_);
685 matrices_->coarsenVector(*lhs_);
686 matrices_->coarsenVector(*update_);
687
688 // Preprocess all smoothers
689 typedef typename Hierarchy<Smoother,A>::Iterator Iterator;
690 typedef typename Hierarchy<Range,A>::Iterator RIterator;
691 typedef typename Hierarchy<Domain,A>::Iterator DIterator;
692 Iterator coarsest = smoothers_->coarsest();
693 Iterator smoother = smoothers_->finest();
694 RIterator rhs = rhs_->finest();
695 DIterator lhs = lhs_->finest();
696 if(smoothers_->levels()>0) {
697
698 assert(lhs_->levels()==rhs_->levels());
699 assert(smoothers_->levels()==lhs_->levels() || matrices_->levels()==matrices_->maxlevels());
700 assert(smoothers_->levels()+1==lhs_->levels() || matrices_->levels()<matrices_->maxlevels());
701
702 if(smoother!=coarsest)
703 for(++smoother, ++lhs, ++rhs; smoother != coarsest; ++smoother, ++lhs, ++rhs)
704 smoother->pre(*lhs,*rhs);
705 smoother->pre(*lhs,*rhs);
706 }
707
708
709 // The preconditioner might change x and b. So we have to
710 // copy the changes to the original vectors.
711 x = *lhs_->finest();
712 b = *rhs_->finest();
713
714 }
715 template<class M, class X, class S, class PI, class A>
717 {
718 return matrices_->levels();
719 }
720 template<class M, class X, class S, class PI, class A>
722 {
723 return matrices_->maxlevels();
724 }
725
727 template<class M, class X, class S, class PI, class A>
729 {
730 OPM_TIMEBLOCK(apply);
731 LevelContext levelContext;
732
733 if(additive) {
734 *(rhs_->finest())=d;
735 additiveMgc();
736 v=*lhs_->finest();
737 }else{
738 // Init all iterators for the current level
739 initIteratorsWithFineLevel(levelContext);
740
741
742 *levelContext.lhs = v;
743 *levelContext.rhs = d;
744 *levelContext.update=0;
745 levelContext.level=0;
746
747 mgc(levelContext);
748
749 if(postSteps_==0||matrices_->maxlevels()==1)
750 levelContext.pinfo->copyOwnerToAll(*levelContext.update, *levelContext.update);
751
752 v=*levelContext.update;
753 }
754
755 }
756
757 template<class M, class X, class S, class PI, class A>
758 void AMGCPR<M,X,S,PI,A>::initIteratorsWithFineLevel(LevelContext& levelContext)
759 {
760 OPM_TIMEBLOCK(initIteratorsWithFineLevel);
761 levelContext.smoother = smoothers_->finest();
762 levelContext.matrix = matrices_->matrices().finest();
763 levelContext.pinfo = matrices_->parallelInformation().finest();
764 levelContext.redist =
765 matrices_->redistributeInformation().begin();
766 levelContext.aggregates = matrices_->aggregatesMaps().begin();
767 levelContext.lhs = lhs_->finest();
768 levelContext.update = update_->finest();
769 levelContext.rhs = rhs_->finest();
770 }
771
772 template<class M, class X, class S, class PI, class A>
773 bool AMGCPR<M,X,S,PI,A>
774 ::moveToCoarseLevel(LevelContext& levelContext)
775 {
776 OPM_TIMEBLOCK(moveToCoarseLevel);
777 bool processNextLevel=true;
778
779 if(levelContext.redist->isSetup()) {
780 levelContext.redist->redistribute(static_cast<const Range&>(*levelContext.rhs),
781 levelContext.rhs.getRedistributed());
782 processNextLevel = levelContext.rhs.getRedistributed().size()>0;
783 if(processNextLevel) {
784 //restrict defect to coarse level right hand side.
785 typename Hierarchy<Range,A>::Iterator fineRhs = levelContext.rhs++;
786 ++levelContext.pinfo;
788 ::restrictVector(*(*levelContext.aggregates), *levelContext.rhs,
789 static_cast<const Range&>(fineRhs.getRedistributed()),
790 *levelContext.pinfo);
791 }
792 }else{
793 //restrict defect to coarse level right hand side.
794 typename Hierarchy<Range,A>::Iterator fineRhs = levelContext.rhs++;
795 ++levelContext.pinfo;
797 ::restrictVector(*(*levelContext.aggregates),
798 *levelContext.rhs, static_cast<const Range&>(*fineRhs),
799 *levelContext.pinfo);
800 }
801
802 if(processNextLevel) {
803 // prepare coarse system
804 ++levelContext.lhs;
805 ++levelContext.update;
806 ++levelContext.matrix;
807 ++levelContext.level;
808 ++levelContext.redist;
809
810 if(levelContext.matrix != matrices_->matrices().coarsest() || matrices_->levels()<matrices_->maxlevels()) {
811 // next level is not the globally coarsest one
812 ++levelContext.smoother;
813 ++levelContext.aggregates;
814 }
815 // prepare the update on the next level
816 *levelContext.update=0;
817 }
818 return processNextLevel;
819 }
820
821 template<class M, class X, class S, class PI, class A>
822 void AMGCPR<M,X,S,PI,A>
823 ::moveToFineLevel(LevelContext& levelContext, bool processNextLevel)
824 {
825 OPM_TIMEBLOCK(moveToFineLevel);
826 if(processNextLevel) {
827 if(levelContext.matrix != matrices_->matrices().coarsest() || matrices_->levels()<matrices_->maxlevels()) {
828 // previous level is not the globally coarsest one
829 --levelContext.smoother;
830 --levelContext.aggregates;
831 }
832 --levelContext.redist;
833 --levelContext.level;
834 //prolongate and add the correction (update is in coarse left hand side)
835 --levelContext.matrix;
836
837 //typename Hierarchy<Domain,A>::Iterator coarseLhs = lhs--;
838 --levelContext.lhs;
839 --levelContext.pinfo;
840 }
841 if(levelContext.redist->isSetup()) {
842 // Need to redistribute during prolongateVector
843 levelContext.lhs.getRedistributed()=0;
845 ::prolongateVector(*(*levelContext.aggregates), *levelContext.update, *levelContext.lhs,
846 levelContext.lhs.getRedistributed(),
847 matrices_->getProlongationDampingFactor(),
848 *levelContext.pinfo, *levelContext.redist);
849 }else{
850 *levelContext.lhs=0;
852 ::prolongateVector(*(*levelContext.aggregates), *levelContext.update, *levelContext.lhs,
853 matrices_->getProlongationDampingFactor(),
854 *levelContext.pinfo);
855 }
856
857
858 if(processNextLevel) {
859 --levelContext.update;
860 --levelContext.rhs;
861 }
862
863 *levelContext.update += *levelContext.lhs;
864 }
865
866 template<class M, class X, class S, class PI, class A>
868 {
869 return IsDirectSolver< CoarseSolver>::value;
870 }
871
872 template<class M, class X, class S, class PI, class A>
873 void AMGCPR<M,X,S,PI,A>::mgc(LevelContext& levelContext){
874 //OPM_TIMEBLOCK(mgc);
875 if(levelContext.matrix == matrices_->matrices().coarsest() && levels()==maxlevels()) {
876 // Solve directly
878 res.converged=true; // If we do not compute this flag will not get updated
879 if(levelContext.redist->isSetup()) {
880 levelContext.redist->redistribute(*levelContext.rhs, levelContext.rhs.getRedistributed());
881 if(levelContext.rhs.getRedistributed().size()>0) {
882 // We are still participating in the computation
883 levelContext.pinfo.getRedistributed().copyOwnerToAll(levelContext.rhs.getRedistributed(),
884 levelContext.rhs.getRedistributed());
885 solver_->apply(levelContext.update.getRedistributed(),
886 levelContext.rhs.getRedistributed(), res);
887 }
888 levelContext.redist->redistributeBackward(*levelContext.update, levelContext.update.getRedistributed());
889 levelContext.pinfo->copyOwnerToAll(*levelContext.update, *levelContext.update);
890 }else{
891 levelContext.pinfo->copyOwnerToAll(*levelContext.rhs, *levelContext.rhs);
892 solver_->apply(*levelContext.update, *levelContext.rhs, res);
893 }
894
895 if (!res.converged)
896 coarsesolverconverged = false;
897 }else{
898 // presmoothing
899 presmooth(levelContext, preSteps_);
900
901#ifndef DUNE_AMG_NO_COARSEGRIDCORRECTION
902 bool processNextLevel = moveToCoarseLevel(levelContext);
903
904 if(processNextLevel) {
905 // next level
906 for(std::size_t i=0; i<gamma_; i++)
907 mgc(levelContext);
908 }
909
910 moveToFineLevel(levelContext, processNextLevel);
911#else
912 *lhs=0;
913#endif
914
915 if(levelContext.matrix == matrices_->matrices().finest()) {
916 coarsesolverconverged = matrices_->parallelInformation().finest()->communicator().prod(coarsesolverconverged);
917 if(!coarsesolverconverged){
918 //DUNE_THROW(MathError, "Coarse solver did not converge");
919 }
920 }
921 // postsmoothing
922 postsmooth(levelContext, postSteps_);
923
924 }
925 }
926
927 template<class M, class X, class S, class PI, class A>
928 void AMGCPR<M,X,S,PI,A>::additiveMgc(){
929 OPM_TIMEBLOCK(additiveMgc);
930 // restrict residual to all levels
931 typename ParallelInformationHierarchy::Iterator pinfo=matrices_->parallelInformation().finest();
932 typename Hierarchy<Range,A>::Iterator rhs=rhs_->finest();
933 typename Hierarchy<Domain,A>::Iterator lhs = lhs_->finest();
934 typename OperatorHierarchy::AggregatesMapList::const_iterator aggregates=matrices_->aggregatesMaps().begin();
935
936 for(typename Hierarchy<Range,A>::Iterator fineRhs=rhs++; fineRhs != rhs_->coarsest(); fineRhs=rhs++, ++aggregates) {
937 ++pinfo;
939 ::restrictVector(*(*aggregates), *rhs, static_cast<const Range&>(*fineRhs), *pinfo);
940 }
941
942 // pinfo is invalid, set to coarsest level
943 //pinfo = matrices_->parallelInformation().coarsest
944 // calculate correction for all levels
945 lhs = lhs_->finest();
946 typename Hierarchy<Smoother,A>::Iterator smoother = smoothers_->finest();
947
948 for(rhs=rhs_->finest(); rhs != rhs_->coarsest(); ++lhs, ++rhs, ++smoother) {
949 // presmoothing
950 *lhs=0;
951 smoother->apply(*lhs, *rhs);
952 }
953
954 // Coarse level solve
955#ifndef DUNE_AMG_NO_COARSEGRIDCORRECTION
957 pinfo->copyOwnerToAll(*rhs, *rhs);
958 solver_->apply(*lhs, *rhs, res);
959
960 if(!res.converged)
961 DUNE_THROW(MathError, "Coarse solver did not converge");
962#else
963 *lhs=0;
964#endif
965 // Prologate and add up corrections from all levels
966 --pinfo;
967 --aggregates;
968
969 for(typename Hierarchy<Domain,A>::Iterator coarseLhs = lhs--; coarseLhs != lhs_->finest(); coarseLhs = lhs--, --aggregates, --pinfo) {
971 ::prolongateVector(*(*aggregates), *coarseLhs, *lhs, 1.0, *pinfo);
972 }
973 }
974
975
977 template<class M, class X, class S, class PI, class A>
978 void AMGCPR<M,X,S,PI,A>::post([[maybe_unused]] Domain& x)
979 {
980 OPM_TIMEBLOCK(post);
981 // Postprocess all smoothers
982 typedef typename Hierarchy<Smoother,A>::Iterator Iterator;
983 typedef typename Hierarchy<Domain,A>::Iterator DIterator;
984 Iterator coarsest = smoothers_->coarsest();
985 Iterator smoother = smoothers_->finest();
986 DIterator lhs = lhs_->finest();
987 if(smoothers_->levels()>0) {
988 if(smoother != coarsest || matrices_->levels()<matrices_->maxlevels())
989 smoother->post(*lhs);
990 if(smoother!=coarsest)
991 for(++smoother, ++lhs; smoother != coarsest; ++smoother, ++lhs)
992 smoother->post(*lhs);
993 smoother->post(*lhs);
994 }
995 //delete &(*lhs_->finest());
996 lhs_.reset();
997 //delete &(*update_->finest());
998 update_.reset();
999 //delete &(*rhs_->finest());
1000 rhs_.reset();
1001 }
1002
1003 template<class M, class X, class S, class PI, class A>
1004 template<class A1>
1005 void AMGCPR<M,X,S,PI,A>::getCoarsestAggregateNumbers(std::vector<std::size_t,A1>& cont)
1006 {
1007 matrices_->getCoarsestAggregatesOnFinest(cont);
1008 }
1009
1010 } // end namespace Amg
1011} // end namespace Dune
1012
1013#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:34
M Operator
The matrix operator type.
Definition: amgcpr.hh:96
Hierarchy< Smoother, A >::Iterator smoother
The iterator over the smoothers.
Definition: amgcpr.hh:301
void post(Domain &x) override
Definition: amgcpr.hh:978
AMGCPR(const OperatorHierarchy &matrices, CoarseSolver &coarseSolver, const SmootherArgs &smootherArgs, const Parameters &parms)
Construct a new amg with a specific coarse solver.
Definition: amgcpr.hh:423
Hierarchy< Domain, A >::Iterator update
The iterator over the updates.
Definition: amgcpr.hh:325
Hierarchy< Range, A >::Iterator rhs
The iterator over the right hand sided.
Definition: amgcpr.hh:329
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:309
void setDirichletPresolve(bool on)
Solve rows without off-diagonal entries directly in pre(), then copy x from the owners.
Definition: amgcpr.hh:161
OperatorHierarchy::ParallelMatrixHierarchy::ConstIterator matrix
The iterator over the matrices.
Definition: amgcpr.hh:305
void getCoarsestAggregateNumbers(std::vector< std::size_t, A1 > &cont)
Get the aggregate number of each unknown on the coarsest level.
Definition: amgcpr.hh:1005
OperatorHierarchy::ParallelInformationHierarchy ParallelInformationHierarchy
The parallal data distribution hierarchy type.
Definition: amgcpr.hh:107
~AMGCPR()
Definition: amgcpr.hh:465
void recalculateHierarchy()
Recalculate the matrix hierarchy.
Definition: amgcpr.hh:205
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:728
X Range
The range type.
Definition: amgcpr.hh:112
void pre(Domain &x, Range &b) override
Definition: amgcpr.hh:627
X Domain
The domain type.
Definition: amgcpr.hh:110
void update() override
Update the coarse solver and the hierarchies.
Definition: amgcpr.hh:483
std::size_t maxlevels()
Definition: amgcpr.hh:721
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:477
bool hasPerfectUpdate() const override
Definition: amgcpr.hh:178
OperatorHierarchy::AggregatesMapList::const_iterator aggregates
The iterator over the aggregates maps.
Definition: amgcpr.hh:317
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:333
Hierarchy< Domain, A >::Iterator lhs
The iterator over the left hand side.
Definition: amgcpr.hh:321
bool usesDirectCoarseLevelSolver() const
Check whether the coarse solver used is a direct solver.
Definition: amgcpr.hh:867
Smoother SmootherType
Definition: amgcpr.hh:297
OperatorHierarchy::RedistributeInfoList::const_iterator redist
The iterator over the redistribution information.
Definition: amgcpr.hh:313
SolverCategory::Category category() const override
Category of the preconditioner (see SolverCategory::Category)
Definition: amgcpr.hh:173
std::size_t levels()
Definition: amgcpr.hh:716
void redistributeMatrixAmg(M &, M &, SequentialInformation &, SequentialInformation &, T &)
Definition: amgcpr.hh:35
Definition: fvbaseprimaryvariables.hh:161
void restrictVector(const GpuVector< T > &fine, GpuVector< T > &coarse, const GpuVector< T > &weights, std::size_t pressureVarIndex)
Restricts a fine level vector to a coarse level vector based on pressure index.
void prolongateVector(const GpuVector< T > &coarse, GpuVector< T > &fine, const GpuVector< T > &weights, std::size_t pressureVarIndex)
Prolongs a coarse level vector to a fine level vector based on pressure index.
Dune::InverseOperatorResult InverseOperatorResult
Definition: GpuBridge.hpp:32