CPRPreconditioner.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2014 SINTEF ICT, Applied Mathematics.
3  Copyright 2014 IRIS AS.
4  Copyright 2015 Dr. Blatt - HPC-Simulation-Software & Services
5  Copyright 2015 NTNU
6  Copyright 2015 Statoil AS
7 
8  This file is part of the Open Porous Media project (OPM).
9 
10  OPM is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  OPM is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with OPM. If not, see <http://www.gnu.org/licenses/>.
22 */
23 
24 #ifndef OPM_CPRPRECONDITIONER_HEADER_INCLUDED
25 #define OPM_CPRPRECONDITIONER_HEADER_INCLUDED
26 
27 #include <memory>
28 #include <type_traits>
29 
30 #include <opm/common/utility/platform_dependent/disable_warnings.h>
31 #include <opm/core/utility/parameters/ParameterGroup.hpp>
32 
33 #include <dune/istl/bvector.hh>
34 #include <dune/istl/bcrsmatrix.hh>
35 #include <dune/istl/operators.hh>
36 #include <dune/istl/io.hh>
37 #include <dune/istl/owneroverlapcopy.hh>
38 #include <dune/istl/preconditioners.hh>
39 #include <dune/istl/schwarz.hh>
40 #include <dune/istl/solvers.hh>
41 #include <dune/istl/paamg/amg.hh>
42 #include <dune/istl/paamg/kamg.hh>
43 #include <dune/istl/paamg/pinfo.hh>
44 
45 #include <opm/common/utility/platform_dependent/reenable_warnings.h>
46 
47 #include <opm/common/ErrorMacros.hpp>
48 #include <opm/common/Exceptions.hpp>
49 
51 namespace Opm
52 {
53 namespace
54 {
63 template<class M, class X, class Y, class P>
64 struct CPRSelector
65 {
67  typedef Dune::Amg::SequentialInformation ParallelInformation;
69  typedef Dune::MatrixAdapter<M, X, Y> Operator;
71  typedef Dune::SeqILU0<M,X,X> EllipticPreconditioner;
73  typedef std::unique_ptr<EllipticPreconditioner> EllipticPreconditionerPointer;
74 
76  typedef EllipticPreconditioner Smoother;
77  typedef Dune::Amg::AMG<Operator, X, Smoother, ParallelInformation> AMG;
78 
82  static Operator* makeOperator(const M& m, const P&)
83  {
84  return new Operator(m);
85  }
86 };
87 
88 #if HAVE_MPI
89 template<class M, class X, class Y, class I1, class I2>
91 struct CPRSelector<M,X,Y,Dune::OwnerOverlapCopyCommunication<I1,I2> >
92 {
94  typedef Dune::OwnerOverlapCopyCommunication<I1,I2> ParallelInformation;
96  typedef Dune::OverlappingSchwarzOperator<M,X,X,ParallelInformation> Operator;
98  typedef Dune::BlockPreconditioner<X, X, ParallelInformation, Dune::SeqILU0<M,X,X> >
99  EllipticPreconditioner;
101  typedef std::unique_ptr<EllipticPreconditioner,
102  AdditionalObjectDeleter<Dune::SeqILU0<M,X,X> > >
103  EllipticPreconditionerPointer;
104 
105  typedef EllipticPreconditioner Smoother;
106  typedef Dune::Amg::AMG<Operator, X, Smoother, ParallelInformation> AMG;
107 
111  static Operator* makeOperator(const M& m, const ParallelInformation& p)
112  {
113  return new Operator(m, p);
114  }
115 };
116 
123 template<class ILU, class I1, class I2>
124 AdditionalObjectDeleter<ILU>
125 createParallelDeleter(ILU& ilu, const Dune::OwnerOverlapCopyCommunication<I1,I2>& p)
126  {
127  (void) p;
128  return AdditionalObjectDeleter<ILU>(ilu);
129  }
130 #endif
131 
135 template<class M, class X>
136 std::shared_ptr<Dune::SeqILU0<M,X,X> >
137 createILU0Ptr(const M& A, double relax, const Dune::Amg::SequentialInformation&)
138 {
139  return std::shared_ptr<Dune::SeqILU0<M,X,X> >(new Dune::SeqILU0<M,X,X>( A, relax) );
140 }
145 template<class M, class X>
146 std::shared_ptr<Dune::SeqILUn<M,X,X> >
147 createILUnPtr(const M& A, int ilu_n, double relax, const Dune::Amg::SequentialInformation&)
148 {
149  return std::shared_ptr<Dune::SeqILUn<M,X,X> >(new Dune::SeqILUn<M,X,X>( A, ilu_n, relax) );
150 }
151 
152 #if HAVE_MPI
153 template<class ILU, class I1, class I2>
154 struct SelectParallelILUSharedPtr
155 {
156  typedef std::shared_ptr<
157  Dune::BlockPreconditioner<
158  typename ILU::range_type,
159  typename ILU::domain_type,
160  Dune::OwnerOverlapCopyCommunication<I1,I2>,
161  ILU
162  >
163  > type;
164 };
165 
170 template<class M, class X, class I1, class I2>
171 typename SelectParallelILUSharedPtr<Dune::SeqILU0<M,X,X>, I1, I2>::type
172 createILU0Ptr(const M& A, double relax,
173  const Dune::OwnerOverlapCopyCommunication<I1,I2>& comm)
174 {
175  typedef Dune::BlockPreconditioner<
176  X,
177  X,
178  Dune::OwnerOverlapCopyCommunication<I1,I2>,
179  Dune::SeqILU0<M,X,X>
180  > PointerType;
181  Dune::SeqILU0<M,X,X>* ilu = nullptr;
182  int ilu_setup_successful = 1;
183  std::string message;
184  try {
185  ilu = new Dune::SeqILU0<M,X,X>(A, relax);
186  }
187  catch ( Dune::MatrixBlockError error )
188  {
189  message = error.what();
190  std::cerr<<"Exception occured on process " <<
191  comm.communicator().rank() << " during " <<
192  "setup of ILU0 preconditioner with message: " <<
193  message<<std::endl;
194  ilu_setup_successful = 0;
195  }
196  // Check whether there was a problem on some process
197  if ( comm.communicator().min(ilu_setup_successful) == 0 )
198  {
199  if ( ilu ) // not null if constructor succeeded
200  {
201  // prevent memory leak
202  delete ilu;
203  }
204  throw Dune::MatrixBlockError();
205  }
206  return typename SelectParallelILUSharedPtr<Dune::SeqILU0<M,X,X>, I1, I2>
207  ::type ( new PointerType(*ilu, comm), createParallelDeleter(*ilu, comm));
208 }
209 
215 template<class M, class X, class I1, class I2>
216 typename SelectParallelILUSharedPtr<Dune::SeqILUn<M,X,X>, I1, I2>::type
217 createILUnPtr(const M& A, int ilu_n, double relax,
218  const Dune::OwnerOverlapCopyCommunication<I1,I2>& comm)
219 {
220  typedef Dune::BlockPreconditioner<
221  X,
222  X,
223  Dune::OwnerOverlapCopyCommunication<I1,I2>,
224  Dune::SeqILUn<M,X,X>
225  > PointerType;
226  Dune::SeqILUn<M,X,X>* ilu = new Dune::SeqILUn<M,X,X>( A, ilu_n, relax);
227 
228  return typename SelectParallelILUSharedPtr<Dune::SeqILUn<M,X,X>, I1, I2>::type
229  (new PointerType(*ilu, comm),createParallelDeleter(*ilu, comm));
230 }
231 #endif
232 
236 template<class M, class X=typename M::range_type>
237 std::unique_ptr<Dune::SeqILU0<M,X,X> >
238 createEllipticPreconditionerPointer(const M& Ae, double relax,
239  const Dune::Amg::SequentialInformation&)
240 {
241  return std::unique_ptr<Dune::SeqILU0<M,X,X> >(new Dune::SeqILU0<M,X,X>(Ae, relax));
242 }
243 
244 #if HAVE_MPI
245 template<class M, class X=typename M::range_type, class I1, class I2>
250 typename CPRSelector<M,X,X,Dune::OwnerOverlapCopyCommunication<I1,I2> >
251 ::EllipticPreconditionerPointer
252 createEllipticPreconditionerPointer(const M& Ae, double relax,
253  const Dune::OwnerOverlapCopyCommunication<I1,I2>& comm)
254 {
255  typedef Dune::BlockPreconditioner<X, X,
256  Dune::OwnerOverlapCopyCommunication<I1,I2>,
257  Dune::SeqILU0<M,X,X> >
258  ParallelPreconditioner;
259 
260  Dune::SeqILU0<M,X,X>* ilu=new Dune::SeqILU0<M,X,X>(Ae, relax);
261  typedef typename CPRSelector<M,X,X,Dune::OwnerOverlapCopyCommunication<I1,I2> >
262  ::EllipticPreconditionerPointer EllipticPreconditionerPointer;
263  return EllipticPreconditionerPointer(new ParallelPreconditioner(*ilu, comm),
264  createParallelDeleter(*ilu, comm));
265 }
266 #endif
267 } // end namespace
268 
270  {
271  double cpr_relax_;
278 
280 
281  CPRParameter( const parameter::ParameterGroup& param)
282  {
283  // reset values to default
284  reset();
285 
286  cpr_relax_ = param.getDefault("cpr_relax", cpr_relax_);
287  cpr_solver_tol_ = param.getDefault("cpr_solver_tol", cpr_solver_tol_);
288  cpr_ilu_n_ = param.getDefault("cpr_ilu_n", cpr_ilu_n_);
289  cpr_max_ell_iter_ = param.getDefault("cpr_max_elliptic_iter",cpr_max_ell_iter_);
290  cpr_use_amg_ = param.getDefault("cpr_use_amg", cpr_use_amg_);
291  cpr_use_bicgstab_ = param.getDefault("cpr_use_bicgstab", cpr_use_bicgstab_);
292  cpr_solver_verbose_ = param.getDefault("cpr_solver_verbose", cpr_solver_verbose_);
293  }
294 
295  void reset()
296  {
297  cpr_relax_ = 1.0;
298  cpr_solver_tol_ = 1e-2;
299  cpr_ilu_n_ = 0;
300  cpr_max_ell_iter_ = 25;
301  cpr_use_amg_ = true;
302  cpr_use_bicgstab_ = true;
303  cpr_solver_verbose_ = false;
304  }
305  };
306 
307 
322  template<class M, class X, class Y,
323  class P=Dune::Amg::SequentialInformation>
324  class CPRPreconditioner : public Dune::Preconditioner<X,Y>
325  {
326  // prohibit copying for now
328 
329  public:
333  typedef typename Dune::remove_const<M>::type matrix_type;
335  typedef X domain_type;
337  typedef Y range_type;
339  typedef typename X::field_type field_type;
340 
341  // define the category
342  enum {
344  category = std::is_same<P,Dune::Amg::SequentialInformation>::value?
345  Dune::SolverCategory::sequential:Dune::SolverCategory::overlapping
346  };
347 
349  typedef typename CPRSelector<M,X,X,P>::Operator Operator;
350 
352  typedef Dune::Preconditioner<X,X> WholeSystemPreconditioner;
353 
356  typedef typename CPRSelector<M,X,X,P>::EllipticPreconditionerPointer
358 
360  typedef typename CPRSelector<M,X,X,P>::AMG AMG;
361 
373  CPRPreconditioner (const CPRParameter& param, const M& A, const M& Ae,
374  const ParallelInformation& comm=ParallelInformation(),
375  const ParallelInformation& commAe=ParallelInformation())
376  : param_( param ),
377  A_(A),
378  Ae_(Ae),
379  de_( Ae_.N() ),
380  ve_( Ae_.M() ),
381  dmodified_( A_.N() ),
382  opAe_(CPRSelector<M,X,Y,P>::makeOperator(Ae_, commAe)),
383  precond_(), // ilu0 preconditioner for elliptic system
384  amg_(), // amg preconditioner for elliptic system
385  pre_(), // copy A will be made be the preconditioner
386  vilu_( A_.N() ),
387  comm_(comm),
388  commAe_(commAe)
389  {
390  // create appropriate preconditioner for elliptic system
392 
393  // create the preconditioner for the whole system.
394  if( param_.cpr_ilu_n_ == 0 ) {
395  pre_ = createILU0Ptr<M,X>( A_, param_.cpr_relax_, comm_ );
396  }
397  else {
398  pre_ = createILUnPtr<M,X>( A_, param_.cpr_ilu_n_, param_.cpr_relax_, comm_ );
399  }
400  }
401 
407  virtual void pre (X& /*x*/, Y& /*b*/)
408  {
409  }
410 
416  virtual void apply (X& v, const Y& d)
417  {
418  // Extract part of d corresponding to elliptic part.
419  // Note: Assumes that the elliptic part comes first.
420  std::copy_n(d.begin(), de_.size(), de_.begin());
421 
422  // Solve elliptic part, extend solution to full.
423  // reset result
424  ve_ = 0;
425  solveElliptic( ve_, de_ );
426 
427  //reset return value
428  v = 0.0;
429  // Again assuming that the elliptic part comes first.
430  std::copy(ve_.begin(), ve_.end(), v.begin());
431 
432  // Subtract elliptic residual from initial residual.
433  // dmodified = d - A * vfull
434  dmodified_ = d;
435  A_.mmv(v, dmodified_);
436  // A is not parallel, do communication manually.
437  comm_.copyOwnerToAll(dmodified_, dmodified_);
438 
439  // Apply Preconditioner for whole system (relax will be applied already)
440  pre_->apply( vilu_, dmodified_);
441 
442  // don't apply relaxation if relax_ == 1
443  if( std::abs( param_.cpr_relax_ - 1.0 ) < 1e-12 ) {
444  v += vilu_;
445  }
446  else {
447  v *= param_.cpr_relax_;
448  v += vilu_;
449  }
450  }
451 
457  virtual void post (X& /*x*/)
458  {
459  }
460 
461  protected:
462  void solveElliptic(Y& x, Y& de)
463  {
464  // Linear solver parameters
465  const double tolerance = param_.cpr_solver_tol_;
466  const int maxit = param_.cpr_max_ell_iter_;
467  const int verbosity = ( param_.cpr_solver_verbose_ &&
468  comm_.communicator().rank()==0 ) ? 1 : 0;
469 
470  // operator result containing iterations etc.
471  Dune::InverseOperatorResult result;
472 
473  // the scalar product chooser
474  typedef Dune::ScalarProductChooser<X,ParallelInformation,category>
475  ScalarProductChooser;
476  // the scalar product.
477  std::unique_ptr<typename ScalarProductChooser::ScalarProduct>
478  sp(ScalarProductChooser::construct(commAe_));
479 
480  if( amg_ )
481  {
482  // Solve system with AMG
483  if( param_.cpr_use_bicgstab_ ) {
484  Dune::BiCGSTABSolver<X> linsolve(*opAe_, *sp, (*amg_), tolerance, maxit, verbosity);
485  linsolve.apply(x, de, result);
486  }
487  else {
488  Dune::CGSolver<X> linsolve(*opAe_, *sp, (*amg_), tolerance, maxit, verbosity);
489  linsolve.apply(x, de, result);
490  }
491  }
492  else
493  {
494  assert( precond_ );
495  // Solve system with ILU-0
496  if( param_.cpr_use_bicgstab_ ) {
497  Dune::BiCGSTABSolver<X> linsolve(*opAe_, *sp, (*precond_), tolerance, maxit, verbosity);
498  linsolve.apply(x, de, result);
499  }
500  else {
501  Dune::CGSolver<X> linsolve(*opAe_, *sp, (*precond_), tolerance, maxit, verbosity);
502  linsolve.apply(x, de, result);
503  }
504 
505  }
506 
507  if (!result.converged) {
508  OPM_THROW(LinearSolverProblem, "CPRPreconditioner failed to solve elliptic subsystem.");
509  }
510  }
511 
514 
516  const matrix_type& A_;
518  const matrix_type& Ae_;
519 
522 
524  std::unique_ptr<Operator> opAe_;
525 
527  EllipticPreconditionerPointer precond_;
529  std::unique_ptr< AMG > amg_;
530 
537  std::shared_ptr< WholeSystemPreconditioner > pre_;
538 
540  Y vilu_;
541 
543  const P& comm_;
546  const P& commAe_;
547  protected:
548  void createEllipticPreconditioner( const bool amg, const P& comm )
549  {
550  if( amg )
551  {
552  // The coupling metric used in the AMG
553  typedef Dune::Amg::FirstDiagonal CouplingMetric;
554 
555  // The coupling criterion used in the AMG
556  typedef Dune::Amg::SymmetricCriterion<M, CouplingMetric> CritBase;
557 
558  // The coarsening criterion used in the AMG
559  typedef Dune::Amg::CoarsenCriterion<CritBase> Criterion;
560 
561  // TODO: revise choice of parameters
562  int coarsenTarget=1200;
563  Criterion criterion(15,coarsenTarget);
564  criterion.setDebugLevel( 0 ); // no debug information, 1 for printing hierarchy information
565  criterion.setDefaultValuesIsotropic(2);
566  criterion.setNoPostSmoothSteps( 1 );
567  criterion.setNoPreSmoothSteps( 1 );
568 
569  // for DUNE 2.2 we also need to pass the smoother args
570  typedef typename AMG::Smoother Smoother;
571  typedef typename Dune::Amg::SmootherTraits<Smoother>::Arguments SmootherArgs;
572  SmootherArgs smootherArgs;
573  smootherArgs.iterations = 1;
574  smootherArgs.relaxationFactor = param_.cpr_relax_;
575 
576  amg_ = std::unique_ptr< AMG > (new AMG(*opAe_, criterion, smootherArgs, comm ));
577  }
578  else
579  {
580  precond_ = createEllipticPreconditionerPointer<M,X>( Ae_, param_.cpr_relax_, comm);
581  }
582  }
583  };
584 
585 
586 } // namespace Opm
587 
588 #endif // OPM_CPRPRECONDITIONER_HEADER_INCLUDED
Dune::Preconditioner< X, X > WholeSystemPreconditioner
preconditioner for the whole system (here either ILU(0) or ILU(n)
Definition: CPRPreconditioner.hpp:352
virtual void apply(X &v, const Y &d)
Apply the preconditoner.
Definition: CPRPreconditioner.hpp:416
int cpr_ilu_n_
Definition: CPRPreconditioner.hpp:273
bool cpr_use_amg_
Definition: CPRPreconditioner.hpp:275
Definition: CPRPreconditioner.hpp:269
Dune::remove_const< M >::type matrix_type
The matrix type the preconditioner is for.
Definition: CPRPreconditioner.hpp:333
Definition: AdditionalObjectDeleter.hpp:22
virtual void post(X &)
Clean up.
Definition: CPRPreconditioner.hpp:457
CPRSelector< M, X, X, P >::Operator Operator
Elliptic Operator.
Definition: CPRPreconditioner.hpp:349
void solveElliptic(Y &x, Y &de)
Definition: CPRPreconditioner.hpp:462
CPRParameter()
Definition: CPRPreconditioner.hpp:279
const matrix_type & Ae_
The elliptic part of the matrix.
Definition: CPRPreconditioner.hpp:518
bool cpr_solver_verbose_
Definition: CPRPreconditioner.hpp:277
std::unique_ptr< Operator > opAe_
elliptic operator
Definition: CPRPreconditioner.hpp:524
The category the preconditioner is part of.
Definition: CPRPreconditioner.hpp:344
CPRPreconditioner(const CPRParameter &param, const M &A, const M &Ae, const ParallelInformation &comm=ParallelInformation(), const ParallelInformation &commAe=ParallelInformation())
Constructor.
Definition: CPRPreconditioner.hpp:373
void reset()
Definition: CPRPreconditioner.hpp:295
Y de_
temporary variables for elliptic solve
Definition: CPRPreconditioner.hpp:521
const P & comm_
The information about the parallelization of the whole system.
Definition: CPRPreconditioner.hpp:543
Y ve_
Definition: CPRPreconditioner.hpp:521
Y vilu_
temporary variables for ILU solve
Definition: CPRPreconditioner.hpp:540
const P & commAe_
The information about the parallelization of the elliptic part of the system.
Definition: CPRPreconditioner.hpp:546
X domain_type
The domain type of the preconditioner.
Definition: CPRPreconditioner.hpp:335
CPRParameter(const parameter::ParameterGroup &param)
Definition: CPRPreconditioner.hpp:281
double cpr_relax_
Definition: CPRPreconditioner.hpp:271
std::unique_ptr< AMG > amg_
AMG preconditioner with ILU0 smoother.
Definition: CPRPreconditioner.hpp:529
CPRSelector< M, X, X, P >::EllipticPreconditionerPointer EllipticPreconditionerPointer
type of the unique pointer to the ilu-0 preconditioner used the for the elliptic system ...
Definition: CPRPreconditioner.hpp:357
double cpr_solver_tol_
Definition: CPRPreconditioner.hpp:272
const CPRParameter & param_
Parameter collection for CPR.
Definition: CPRPreconditioner.hpp:513
Definition: AutoDiffMatrix.hpp:43
P ParallelInformation
The type describing the parallel information.
Definition: CPRPreconditioner.hpp:331
bool cpr_use_bicgstab_
Definition: CPRPreconditioner.hpp:276
Y range_type
The range type of the preconditioner.
Definition: CPRPreconditioner.hpp:337
ADB::M M
Definition: BlackoilModelBase_impl.hpp:85
CPRSelector< M, X, X, P >::AMG AMG
amg preconditioner for the elliptic system
Definition: CPRPreconditioner.hpp:360
Y dmodified_
Definition: CPRPreconditioner.hpp:521
X::field_type field_type
The field type of the preconditioner.
Definition: CPRPreconditioner.hpp:339
virtual void pre(X &, Y &)
Prepare the preconditioner.
Definition: CPRPreconditioner.hpp:407
void createEllipticPreconditioner(const bool amg, const P &comm)
Definition: CPRPreconditioner.hpp:548
int cpr_max_ell_iter_
Definition: CPRPreconditioner.hpp:274
std::shared_ptr< WholeSystemPreconditioner > pre_
The preconditioner for the whole system.
Definition: CPRPreconditioner.hpp:537
const matrix_type & A_
The matrix for the full linear problem.
Definition: CPRPreconditioner.hpp:516
CPR preconditioner.
Definition: CPRPreconditioner.hpp:324
EllipticPreconditionerPointer precond_
ILU0 preconditioner for the elliptic system.
Definition: CPRPreconditioner.hpp:527