opm-simulators
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 
9 #include <opm/simulators/linalg/PreconditionerWithUpdate.hpp>
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 
27 namespace 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>
73  class KAmgTwoGrid;
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  {
291  typedef Smoother SmootherType;
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  if (*col != zero) {
641  diagonal = *col;
642  hasDiagonal = true;
643  } else {
644  break;
645  }
646  }else{
647  if (*col != zero) {
648  isDirichlet = false;
649  break;
650  }
651  }
652  }
653  if(isDirichlet && hasDiagonal)
654  diagonal.solve(x[row.index()], b[row.index()]);
655  }
656 
657  if(smoothers_->levels()>0)
658  smoothers_->finest()->pre(x,b);
659  else
660  // No smoother to make x consistent! Do it by hand
661  matrices_->parallelInformation().coarsest()->copyOwnerToAll(x,x);
662 
663 
664  typedef std::shared_ptr< Range > RangePtr ;
665  typedef std::shared_ptr< Domain > DomainPtr;
666 
667  // Hierarchy takes ownership of pointers
668  RangePtr copy( new Range(b) );
669  rhs_.reset( new Hierarchy<Range,A>(copy) );
670  DomainPtr dcopy( new Domain(x) );
671  lhs_.reset( new Hierarchy<Domain,A>(dcopy) );
672  DomainPtr dcopy2( new Domain(x) );
673  update_.reset( new Hierarchy<Domain,A>(dcopy2) );
674 
675  matrices_->coarsenVector(*rhs_);
676  matrices_->coarsenVector(*lhs_);
677  matrices_->coarsenVector(*update_);
678 
679  // Preprocess all smoothers
680  typedef typename Hierarchy<Smoother,A>::Iterator Iterator;
681  typedef typename Hierarchy<Range,A>::Iterator RIterator;
682  typedef typename Hierarchy<Domain,A>::Iterator DIterator;
683  Iterator coarsest = smoothers_->coarsest();
684  Iterator smoother = smoothers_->finest();
685  RIterator rhs = rhs_->finest();
686  DIterator lhs = lhs_->finest();
687  if(smoothers_->levels()>0) {
688 
689  assert(lhs_->levels()==rhs_->levels());
690  assert(smoothers_->levels()==lhs_->levels() || matrices_->levels()==matrices_->maxlevels());
691  assert(smoothers_->levels()+1==lhs_->levels() || matrices_->levels()<matrices_->maxlevels());
692 
693  if(smoother!=coarsest)
694  for(++smoother, ++lhs, ++rhs; smoother != coarsest; ++smoother, ++lhs, ++rhs)
695  smoother->pre(*lhs,*rhs);
696  smoother->pre(*lhs,*rhs);
697  }
698 
699 
700  // The preconditioner might change x and b. So we have to
701  // copy the changes to the original vectors.
702  x = *lhs_->finest();
703  b = *rhs_->finest();
704 
705  }
706  template<class M, class X, class S, class PI, class A>
707  std::size_t AMGCPR<M,X,S,PI,A>::levels()
708  {
709  return matrices_->levels();
710  }
711  template<class M, class X, class S, class PI, class A>
712  std::size_t AMGCPR<M,X,S,PI,A>::maxlevels()
713  {
714  return matrices_->maxlevels();
715  }
716 
718  template<class M, class X, class S, class PI, class A>
720  {
721  OPM_TIMEBLOCK(apply);
722  LevelContext levelContext;
723 
724  if(additive) {
725  *(rhs_->finest())=d;
726  additiveMgc();
727  v=*lhs_->finest();
728  }else{
729  // Init all iterators for the current level
730  initIteratorsWithFineLevel(levelContext);
731 
732 
733  *levelContext.lhs = v;
734  *levelContext.rhs = d;
735  *levelContext.update=0;
736  levelContext.level=0;
737 
738  mgc(levelContext);
739 
740  if(postSteps_==0||matrices_->maxlevels()==1)
741  levelContext.pinfo->copyOwnerToAll(*levelContext.update, *levelContext.update);
742 
743  v=*levelContext.update;
744  }
745 
746  }
747 
748  template<class M, class X, class S, class PI, class A>
749  void AMGCPR<M,X,S,PI,A>::initIteratorsWithFineLevel(LevelContext& levelContext)
750  {
751  OPM_TIMEBLOCK(initIteratorsWithFineLevel);
752  levelContext.smoother = smoothers_->finest();
753  levelContext.matrix = matrices_->matrices().finest();
754  levelContext.pinfo = matrices_->parallelInformation().finest();
755  levelContext.redist =
756  matrices_->redistributeInformation().begin();
757  levelContext.aggregates = matrices_->aggregatesMaps().begin();
758  levelContext.lhs = lhs_->finest();
759  levelContext.update = update_->finest();
760  levelContext.rhs = rhs_->finest();
761  }
762 
763  template<class M, class X, class S, class PI, class A>
764  bool AMGCPR<M,X,S,PI,A>
765  ::moveToCoarseLevel(LevelContext& levelContext)
766  {
767  OPM_TIMEBLOCK(moveToCoarseLevel);
768  bool processNextLevel=true;
769 
770  if(levelContext.redist->isSetup()) {
771  levelContext.redist->redistribute(static_cast<const Range&>(*levelContext.rhs),
772  levelContext.rhs.getRedistributed());
773  processNextLevel = levelContext.rhs.getRedistributed().size()>0;
774  if(processNextLevel) {
775  //restrict defect to coarse level right hand side.
776  typename Hierarchy<Range,A>::Iterator fineRhs = levelContext.rhs++;
777  ++levelContext.pinfo;
778  Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
779  ::restrictVector(*(*levelContext.aggregates), *levelContext.rhs,
780  static_cast<const Range&>(fineRhs.getRedistributed()),
781  *levelContext.pinfo);
782  }
783  }else{
784  //restrict defect to coarse level right hand side.
785  typename Hierarchy<Range,A>::Iterator fineRhs = levelContext.rhs++;
786  ++levelContext.pinfo;
787  Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
788  ::restrictVector(*(*levelContext.aggregates),
789  *levelContext.rhs, static_cast<const Range&>(*fineRhs),
790  *levelContext.pinfo);
791  }
792 
793  if(processNextLevel) {
794  // prepare coarse system
795  ++levelContext.lhs;
796  ++levelContext.update;
797  ++levelContext.matrix;
798  ++levelContext.level;
799  ++levelContext.redist;
800 
801  if(levelContext.matrix != matrices_->matrices().coarsest() || matrices_->levels()<matrices_->maxlevels()) {
802  // next level is not the globally coarsest one
803  ++levelContext.smoother;
804  ++levelContext.aggregates;
805  }
806  // prepare the update on the next level
807  *levelContext.update=0;
808  }
809  return processNextLevel;
810  }
811 
812  template<class M, class X, class S, class PI, class A>
813  void AMGCPR<M,X,S,PI,A>
814  ::moveToFineLevel(LevelContext& levelContext, bool processNextLevel)
815  {
816  OPM_TIMEBLOCK(moveToFineLevel);
817  if(processNextLevel) {
818  if(levelContext.matrix != matrices_->matrices().coarsest() || matrices_->levels()<matrices_->maxlevels()) {
819  // previous level is not the globally coarsest one
820  --levelContext.smoother;
821  --levelContext.aggregates;
822  }
823  --levelContext.redist;
824  --levelContext.level;
825  //prolongate and add the correction (update is in coarse left hand side)
826  --levelContext.matrix;
827 
828  //typename Hierarchy<Domain,A>::Iterator coarseLhs = lhs--;
829  --levelContext.lhs;
830  --levelContext.pinfo;
831  }
832  if(levelContext.redist->isSetup()) {
833  // Need to redistribute during prolongateVector
834  levelContext.lhs.getRedistributed()=0;
835  Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
836  ::prolongateVector(*(*levelContext.aggregates), *levelContext.update, *levelContext.lhs,
837  levelContext.lhs.getRedistributed(),
838  matrices_->getProlongationDampingFactor(),
839  *levelContext.pinfo, *levelContext.redist);
840  }else{
841  *levelContext.lhs=0;
842  Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
843  ::prolongateVector(*(*levelContext.aggregates), *levelContext.update, *levelContext.lhs,
844  matrices_->getProlongationDampingFactor(),
845  *levelContext.pinfo);
846  }
847 
848 
849  if(processNextLevel) {
850  --levelContext.update;
851  --levelContext.rhs;
852  }
853 
854  *levelContext.update += *levelContext.lhs;
855  }
856 
857  template<class M, class X, class S, class PI, class A>
859  {
860  return IsDirectSolver< CoarseSolver>::value;
861  }
862 
863  template<class M, class X, class S, class PI, class A>
864  void AMGCPR<M,X,S,PI,A>::mgc(LevelContext& levelContext){
865  //OPM_TIMEBLOCK(mgc);
866  if(levelContext.matrix == matrices_->matrices().coarsest() && levels()==maxlevels()) {
867  // Solve directly
868  InverseOperatorResult res;
869  res.converged=true; // If we do not compute this flag will not get updated
870  if(levelContext.redist->isSetup()) {
871  levelContext.redist->redistribute(*levelContext.rhs, levelContext.rhs.getRedistributed());
872  if(levelContext.rhs.getRedistributed().size()>0) {
873  // We are still participating in the computation
874  levelContext.pinfo.getRedistributed().copyOwnerToAll(levelContext.rhs.getRedistributed(),
875  levelContext.rhs.getRedistributed());
876  solver_->apply(levelContext.update.getRedistributed(),
877  levelContext.rhs.getRedistributed(), res);
878  }
879  levelContext.redist->redistributeBackward(*levelContext.update, levelContext.update.getRedistributed());
880  levelContext.pinfo->copyOwnerToAll(*levelContext.update, *levelContext.update);
881  }else{
882  levelContext.pinfo->copyOwnerToAll(*levelContext.rhs, *levelContext.rhs);
883  solver_->apply(*levelContext.update, *levelContext.rhs, res);
884  }
885 
886  if (!res.converged)
887  coarsesolverconverged = false;
888  }else{
889  // presmoothing
890  presmooth(levelContext, preSteps_);
891 
892 #ifndef DUNE_AMG_NO_COARSEGRIDCORRECTION
893  bool processNextLevel = moveToCoarseLevel(levelContext);
894 
895  if(processNextLevel) {
896  // next level
897  for(std::size_t i=0; i<gamma_; i++)
898  mgc(levelContext);
899  }
900 
901  moveToFineLevel(levelContext, processNextLevel);
902 #else
903  *lhs=0;
904 #endif
905 
906  if(levelContext.matrix == matrices_->matrices().finest()) {
907  coarsesolverconverged = matrices_->parallelInformation().finest()->communicator().prod(coarsesolverconverged);
908  if(!coarsesolverconverged){
909  //DUNE_THROW(MathError, "Coarse solver did not converge");
910  }
911  }
912  // postsmoothing
913  postsmooth(levelContext, postSteps_);
914 
915  }
916  }
917 
918  template<class M, class X, class S, class PI, class A>
919  void AMGCPR<M,X,S,PI,A>::additiveMgc(){
920  OPM_TIMEBLOCK(additiveMgc);
921  // restrict residual to all levels
922  typename ParallelInformationHierarchy::Iterator pinfo=matrices_->parallelInformation().finest();
923  typename Hierarchy<Range,A>::Iterator rhs=rhs_->finest();
924  typename Hierarchy<Domain,A>::Iterator lhs = lhs_->finest();
925  typename OperatorHierarchy::AggregatesMapList::const_iterator aggregates=matrices_->aggregatesMaps().begin();
926 
927  for(typename Hierarchy<Range,A>::Iterator fineRhs=rhs++; fineRhs != rhs_->coarsest(); fineRhs=rhs++, ++aggregates) {
928  ++pinfo;
929  Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
930  ::restrictVector(*(*aggregates), *rhs, static_cast<const Range&>(*fineRhs), *pinfo);
931  }
932 
933  // pinfo is invalid, set to coarsest level
934  //pinfo = matrices_->parallelInformation().coarsest
935  // calculate correction for all levels
936  lhs = lhs_->finest();
937  typename Hierarchy<Smoother,A>::Iterator smoother = smoothers_->finest();
938 
939  for(rhs=rhs_->finest(); rhs != rhs_->coarsest(); ++lhs, ++rhs, ++smoother) {
940  // presmoothing
941  *lhs=0;
942  smoother->apply(*lhs, *rhs);
943  }
944 
945  // Coarse level solve
946 #ifndef DUNE_AMG_NO_COARSEGRIDCORRECTION
947  InverseOperatorResult res;
948  pinfo->copyOwnerToAll(*rhs, *rhs);
949  solver_->apply(*lhs, *rhs, res);
950 
951  if(!res.converged)
952  DUNE_THROW(MathError, "Coarse solver did not converge");
953 #else
954  *lhs=0;
955 #endif
956  // Prologate and add up corrections from all levels
957  --pinfo;
958  --aggregates;
959 
960  for(typename Hierarchy<Domain,A>::Iterator coarseLhs = lhs--; coarseLhs != lhs_->finest(); coarseLhs = lhs--, --aggregates, --pinfo) {
961  Transfer<typename OperatorHierarchy::AggregatesMap::AggregateDescriptor,Range,ParallelInformation>
962  ::prolongateVector(*(*aggregates), *coarseLhs, *lhs, 1.0, *pinfo);
963  }
964  }
965 
966 
968  template<class M, class X, class S, class PI, class A>
969  void AMGCPR<M,X,S,PI,A>::post([[maybe_unused]] Domain& x)
970  {
971  OPM_TIMEBLOCK(post);
972  // Postprocess all smoothers
973  typedef typename Hierarchy<Smoother,A>::Iterator Iterator;
974  typedef typename Hierarchy<Domain,A>::Iterator DIterator;
975  Iterator coarsest = smoothers_->coarsest();
976  Iterator smoother = smoothers_->finest();
977  DIterator lhs = lhs_->finest();
978  if(smoothers_->levels()>0) {
979  if(smoother != coarsest || matrices_->levels()<matrices_->maxlevels())
980  smoother->post(*lhs);
981  if(smoother!=coarsest)
982  for(++smoother, ++lhs; smoother != coarsest; ++smoother, ++lhs)
983  smoother->post(*lhs);
984  smoother->post(*lhs);
985  }
986  //delete &(*lhs_->finest());
987  lhs_.reset();
988  //delete &(*update_->finest());
989  update_.reset();
990  //delete &(*rhs_->finest());
991  rhs_.reset();
992  }
993 
994  template<class M, class X, class S, class PI, class A>
995  template<class A1>
996  void AMGCPR<M,X,S,PI,A>::getCoarsestAggregateNumbers(std::vector<std::size_t,A1>& cont)
997  {
998  matrices_->getCoarsestAggregatesOnFinest(cont);
999  }
1000 
1001  } // end namespace Amg
1002 } // end namespace Dune
1003 
1004 #endif
void getCoarsestAggregateNumbers(std::vector< std::size_t, A1 > &cont)
Get the aggregate number of each unknown on the coarsest level.
Definition: amgcpr.hh:996
void pre(Domain &x, Range &b) override
Definition: amgcpr.hh:619
S Smoother
The type of the smoother.
Definition: amgcpr.hh:120
SolverCategory::Category category() const override
Category of the preconditioner (see SolverCategory::Category)
Definition: amgcpr.hh:167
OperatorHierarchy::RedistributeInfoList::const_iterator redist
The iterator over the redistribution information.
Definition: amgcpr.hh:307
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
InverseOperator< X, X > CoarseSolver
the type of the coarse solver.
Definition: amgcpr.hh:114
Definition: fvbaseprimaryvariables.hh:161
void apply(Domain &v, const Range &d) override
Definition: amgcpr.hh:719
SmootherTraits< Smoother >::Arguments SmootherArgs
The argument type for the construction of the smoother.
Definition: amgcpr.hh:123
bool usesDirectCoarseLevelSolver() const
Check whether the coarse solver used is a direct solver.
Definition: amgcpr.hh:858
std::size_t level
The level index.
Definition: amgcpr.hh:327
Definition: amgcpr.hh:73
MatrixHierarchy< M, ParallelInformation, A > OperatorHierarchy
The operator hierarchy type.
Definition: amgcpr.hh:105
X Range
The range type.
Definition: amgcpr.hh:112
PI ParallelInformation
The type of the parallel information.
Definition: amgcpr.hh:103
Hierarchy< Smoother, A >::Iterator smoother
The iterator over the smoothers.
Definition: amgcpr.hh:295
Definition: amgcpr.hh:70
M Operator
The matrix operator type.
Definition: amgcpr.hh:96
OperatorHierarchy::ParallelMatrixHierarchy::ConstIterator matrix
The iterator over the matrices.
Definition: amgcpr.hh:299
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:33
void post(Domain &x) override
Definition: amgcpr.hh:969
Hierarchy< Domain, A >::Iterator update
The iterator over the updates.
Definition: amgcpr.hh:319
OperatorHierarchy::AggregatesMapList::const_iterator aggregates
The iterator over the aggregates maps.
Definition: amgcpr.hh:311
Hierarchy< Domain, A >::Iterator lhs
The iterator over the left hand side.
Definition: amgcpr.hh:315
ParallelInformationHierarchy::Iterator pinfo
The iterator over the parallel information.
Definition: amgcpr.hh:303
void update() override
Update the coarse solver and the hierarchies.
Definition: amgcpr.hh:475
X Domain
The domain type.
Definition: amgcpr.hh:110
void updateSolver(C &criterion, const Operator &, const PI &pinfo)
Update the coarse solver and the hierarchies.
Definition: amgcpr.hh:469
void recalculateHierarchy()
Recalculate the matrix hierarchy.
Definition: amgcpr.hh:199
Hierarchy< Range, A >::Iterator rhs
The iterator over the right hand sided.
Definition: amgcpr.hh:323
OperatorHierarchy::ParallelInformationHierarchy ParallelInformationHierarchy
The parallal data distribution hierarchy type.
Definition: amgcpr.hh:107
Parallel algebraic multigrid based on agglomeration.
Definition: amgcpr.hh:87