parallelamgbackend.hh
Go to the documentation of this file.
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  Copyright (C) 2008-2013 by Andreas Lauser
5 
6  This file is part of the Open Porous Media project (OPM).
7 
8  OPM is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 2 of the License, or
11  (at your option) any later version.
12 
13  OPM is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with OPM. If not, see <http://www.gnu.org/licenses/>.
20 */
25 #ifndef EWOMS_PARALLEL_AMG_BACKEND_HH
26 #define EWOMS_PARALLEL_AMG_BACKEND_HH
27 
39 
40 #include <dune/istl/preconditioners.hh>
41 #include <dune/istl/solvers.hh>
42 #include <dune/istl/paamg/amg.hh>
43 #include <dune/istl/paamg/pinfo.hh>
44 #include <dune/istl/schwarz.hh>
45 #include <dune/istl/owneroverlapcopy.hh>
46 
47 #include <dune/common/parallel/indexset.hh>
48 #include <dune/common/version.hh>
49 #if DUNE_VERSION_NEWER(DUNE_COMMON, 2, 3)
50 #include <dune/common/parallel/mpicollectivecommunication.hh>
51 #else
52 #include <dune/common/mpicollectivecommunication.hh>
53 #endif
54 
55 #include <iostream>
56 
57 namespace Ewoms {
58 namespace Linear {
59 template <class TypeTag>
61 }
62 
63 namespace Properties {
64 NEW_TYPE_TAG(ParallelAmgLinearSolver, INHERITS_FROM(ParallelIterativeLinearSolver));
65 
66 NEW_PROP_TAG(AmgCoarsenTarget);
67 
70 SET_INT_PROP(ParallelAmgLinearSolver, AmgCoarsenTarget, 5000);
71 
72 SET_TYPE_PROP(ParallelAmgLinearSolver, LinearSolverBackend,
74 } // namespace Properties
75 
76 namespace Linear {
83 template <class TypeTag>
84 class ParallelAmgBackend
85 {
86  typedef typename GET_PROP_TYPE(TypeTag, LinearSolverBackend) Implementation;
87 
88  typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
89  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
90  typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) Matrix;
91  typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) Vector;
92  typedef typename GET_PROP_TYPE(TypeTag, BorderListCreator) BorderListCreator;
93  typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
94 
95  typedef typename GET_PROP_TYPE(TypeTag, Overlap) Overlap;
96  typedef typename GET_PROP_TYPE(TypeTag, OverlappingVector) OverlappingVector;
97  typedef typename GET_PROP_TYPE(TypeTag, OverlappingMatrix) OverlappingMatrix;
98 
99 
100  // define the smoother used for the AMG and specify its
101  // arguments
102  typedef Dune::SeqSOR<Matrix, Vector, Vector> SequentialSmoother;
103 // typedef Dune::SeqSSOR<Matrix,Vector,Vector> SequentialSmoother;
104 // typedef Dune::SeqJac<Matrix,Vector,Vector> SequentialSmoother;
105 // typedef Dune::SeqILU0<Matrix,Vector,Vector> SequentialSmoother;
106 // typedef Dune::SeqILUn<Matrix,Vector,Vector> SequentialSmoother;
107 
108 #if HAVE_MPI
109  typedef Dune::OwnerOverlapCopyCommunication<Ewoms::Linear::Index>
110  OwnerOverlapCopyCommunication;
111  typedef Dune::OverlappingSchwarzOperator<Matrix, Vector, Vector,
112  OwnerOverlapCopyCommunication>
113  FineOperator;
114  typedef Dune::OverlappingSchwarzScalarProduct<Vector,
115  OwnerOverlapCopyCommunication> FineScalarProduct;
116  typedef Dune::BlockPreconditioner<Vector,
117  Vector,
118  OwnerOverlapCopyCommunication,
119  SequentialSmoother> ParallelSmoother;
120  typedef Dune::Amg::AMG<FineOperator,
121  Vector,
122  ParallelSmoother,
123  OwnerOverlapCopyCommunication> AMG;
124 #else
125  typedef Dune::MatrixAdapter<Matrix, Vector, Vector> FineOperator;
126  typedef Dune::SeqScalarProduct<Vector> FineScalarProduct;
127  typedef SequentialSmoother ParallelSmoother;
128  typedef Dune::Amg::AMG<FineOperator, Vector, ParallelSmoother> AMG;
129 #endif
130 
131 public:
132  ParallelAmgBackend(const Simulator &simulator)
133  : simulator_(simulator)
134  {
135  overlappingMatrix_ = nullptr;
136  overlappingb_ = nullptr;
137  overlappingx_ = nullptr;
138 
139  amg_ = nullptr;
140  }
141 
143  { cleanup_(); }
144 
145  static void registerParameters()
146  {
148 
149  EWOMS_REGISTER_PARAM(TypeTag, int, AmgCoarsenTarget,
150  "The coarsening target for the agglomerations of "
151  "the AMG preconditioner");
152  }
153 
162  void setStructureMatrix(const Matrix &M)
163  {
164  cleanup_();
165  prepare_();
166  }
167 
173  bool solve(const Matrix &M, Vector &x, Vector &b)
174  {
175  int verbosity = 0;
176  if (simulator_.gridManager().gridView().comm().rank() == 0)
177  verbosity = EWOMS_GET_PARAM(TypeTag, int, LinearSolverVerbosity);
178 
180  // set-up the overlapping matrix and vector
182 
183  if (!overlappingMatrix_) {
184  // make sure that the overlapping matrix and block vectors
185  // have been created
186  prepare_(M);
187  }
188 
189  // copy the values of the non-overlapping linear system of
190  // equations to the overlapping one. On ther border, we add up
191  // the values of all processes (using the assignAdd() methods)
192  overlappingMatrix_->assignAdd(M);
193  overlappingb_->assignAddBorder(b);
194 
195  // copy the result back to the non-overlapping vector. This is
196  // necessary here as assignAddBorder() might modify the
197  // residual vector for the border entities and we need the
198  // "globalized" residual in b...
199  overlappingb_->assignTo(b);
200 
201  (*overlappingx_) = 0.0;
202 
204  // set-up the AMG preconditioner
206  // create the parallel scalar product and the parallel operator
207 #if HAVE_MPI
208  FineOperator fineOperator(*overlappingMatrix_, *istlComm_);
209 #else
210  FineOperator fineOperator(*overlappingMatrix_);
211 #endif
212 
213 #if HAVE_MPI
214  FineScalarProduct scalarProduct(*istlComm_);
215 #else
216  FineScalarProduct scalarProduct;
217 #endif
218 
219  setupAmg_(fineOperator);
220 
222  // set-up the linear solver
224  if (verbosity > 1 && simulator_.gridManager().gridView().comm().rank() == 0)
225  std::cout << "Creating the solver\n" << std::flush;
226 
227  typedef Ewoms::BiCGSTABSolver<Vector> SolverType;
228  Scalar linearSolverTolerance = EWOMS_GET_PARAM(TypeTag, Scalar, LinearSolverTolerance);
229  int maxIterations = EWOMS_GET_PARAM(TypeTag, int, LinearSolverMaxIterations);
230  SolverType solver(fineOperator,
231  scalarProduct,
232  /*preconditioner=*/*amg_,
233  linearSolverTolerance,
234  /*maxSteps=*/maxIterations,
235  verbosity);
236 
238  // create a residual reduction convergence criterion
239 
240  // set the weighting of the residuals
241  OverlappingVector residWeightVec(*overlappingx_);
242  residWeightVec = 0.0;
243  const auto &overlap = overlappingMatrix_->overlap();
244  for (unsigned localIdx = 0; localIdx < unsigned(overlap.numLocal()); ++localIdx) {
245  int nativeIdx = overlap.domesticToNative(localIdx);
246  for (int eqIdx = 0; eqIdx < Vector::block_type::dimension; ++eqIdx) {
247  residWeightVec[localIdx][eqIdx] =
248  this->simulator_.model().eqWeight(nativeIdx, eqIdx);
249  }
250  }
251 
252  Scalar linearSolverAbsTolerance = simulator_.model().newtonMethod().tolerance() / 100.0;
253  Scalar linearSolverFixPointTolerance = 100*std::numeric_limits<Scalar>::epsilon();
254  typedef typename GridView::CollectiveCommunication Comm;
255  auto *convCrit =
257  simulator_.gridView().comm(),
258  residWeightVec,
259  /*fixPointTolerance=*/linearSolverFixPointTolerance,
260  /*residualReductionTolerance=*/linearSolverTolerance,
261  /*absoluteResidualTolerance=*/linearSolverAbsTolerance);
262 
263  // done creating the convergence criterion
265 
266  // tell the linear solver to use it
268  solver.setConvergenceCriterion(std::shared_ptr<ConvergenceCriterion>(convCrit));
269 
270  Dune::InverseOperatorResult result;
271  int solverSucceeded = 1;
272  try
273  {
274  solver.apply(*overlappingx_, *overlappingb_, result);
275  solverSucceeded = simulator_.gridManager().gridView().comm().min(solverSucceeded);
276  }
277  catch (const Dune::Exception &)
278  {
279  solverSucceeded = 0;
280  solverSucceeded = simulator_.gridManager().gridView().comm().min(solverSucceeded);
281  }
282 
283  if (!solverSucceeded)
284  return false;
285 
286  // copy the result back to the non-overlapping vector
287  overlappingx_->assignTo(x);
288 
289  return result.converged;
290  }
291 
292 private:
293  Implementation &asImp_()
294  { return *static_cast<Implementation *>(this); }
295 
296  const Implementation &asImp_() const
297  { return *static_cast<const Implementation *>(this); }
298 
299  void prepare_(const Matrix &M)
300  {
301  BorderListCreator borderListCreator(simulator_.gridView(),
302  simulator_.model().dofMapper());
303 
304  auto &blackList = borderListCreator.blackList();
305 
306  // create the overlapping Jacobian matrix
307  int overlapSize = EWOMS_GET_PARAM(TypeTag, int, LinearSolverOverlapSize);
308  overlappingMatrix_ = new OverlappingMatrix(M,
309  borderListCreator.borderList(),
310  blackList,
311  overlapSize);
312 
313  // create the overlapping vectors for the residual and the
314  // solution
315  overlappingb_ = new OverlappingVector(overlappingMatrix_->overlap());
316  overlappingx_ = new OverlappingVector(*overlappingb_);
317 
318  // writeOverlapToVTK_();
319 
320 #if HAVE_MPI
321  // create and initialize DUNE's OwnerOverlapCopyCommunication
322  // using the domestic overlap
323  istlComm_ = new OwnerOverlapCopyCommunication(MPI_COMM_WORLD);
324  setupAmgIndexSet_(overlappingMatrix_->overlap(), istlComm_->indexSet());
325  istlComm_->remoteIndices().template rebuild<false>();
326 #endif
327  }
328 
329  void cleanup_()
330  {
331  // create the overlapping Jacobian matrix and vectors
332  delete overlappingMatrix_;
333  delete overlappingb_;
334  delete overlappingx_;
335  delete amg_;
336 
337  overlappingMatrix_ = nullptr;
338  overlappingb_ = nullptr;
339  overlappingx_ = nullptr;
340  amg_ = nullptr;
341  }
342 
343 #if HAVE_MPI
344  template <class ParallelIndexSet>
345  void setupAmgIndexSet_(const Overlap &overlap, ParallelIndexSet &istlIndices)
346  {
347  typedef Dune::OwnerOverlapCopyAttributeSet GridAttributes;
348  typedef Dune::OwnerOverlapCopyAttributeSet::AttributeSet GridAttributeSet;
349 
350  // create DUNE's ParallelIndexSet from a domestic overlap
351  istlIndices.beginResize();
352  for (int curIdx = 0; curIdx < overlap.numDomestic(); ++curIdx) {
353  GridAttributeSet gridFlag = overlap.iAmMasterOf(curIdx)
354  ? GridAttributes::owner
355  : GridAttributes::copy;
356 
357  // an index is used by other processes if it is in the
358  // domestic or in the foreign overlap.
359  bool isShared = overlap.isInOverlap(curIdx);
360 
361  assert(curIdx == int(overlap.globalToDomestic(
362  overlap.domesticToGlobal(curIdx))));
363  istlIndices.add(/*globalIdx=*/overlap.domesticToGlobal(curIdx),
364  Dune::ParallelLocalIndex<GridAttributeSet>(
365  curIdx, gridFlag, isShared));
366  }
367  istlIndices.endResize();
368  }
369 #endif
370 
371  void setupAmg_(FineOperator &fineOperator)
372  {
373  if (amg_)
374  return;
375 
376  int verbosity = 0;
377  if (simulator_.gridManager().gridView().comm().rank() == 0)
378  verbosity = EWOMS_GET_PARAM(TypeTag, int, LinearSolverVerbosity);
379 
380  int rank = simulator_.gridManager().gridView().comm().rank();
381  if (verbosity > 1 && rank == 0)
382  std::cout << "Setting up the AMG preconditioner\n";
383 
384  typedef typename Dune::Amg::SmootherTraits<ParallelSmoother>::Arguments
385  SmootherArgs;
386 
387  SmootherArgs smootherArgs;
388  smootherArgs.iterations = 1;
389  smootherArgs.relaxationFactor = 1.0;
390 
391  // specify the coarsen criterion:
392  //
393  // typedef
394  // Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<Matrix,
395  // Dune::Amg::FirstDiagonal>>
396  typedef Dune::Amg::
397  CoarsenCriterion<Dune::Amg::SymmetricCriterion<Matrix, Dune::Amg::FrobeniusNorm> >
398  CoarsenCriterion;
399  int coarsenTarget = EWOMS_GET_PARAM(TypeTag, int, AmgCoarsenTarget);
400  CoarsenCriterion coarsenCriterion(/*maxLevel=*/15, coarsenTarget);
401  coarsenCriterion.setDefaultValuesAnisotropic(GridView::dimension,
402  /*aggregateSizePerDim=*/3);
403  if (verbosity > 0)
404  coarsenCriterion.setDebugLevel(1);
405  else
406  coarsenCriterion.setDebugLevel(0); // make the AMG shut up
407 
408  // reduce the minium coarsen rate (default is 1.2)
409  coarsenCriterion.setMinCoarsenRate(1.05);
410  // coarsenCriterion.setAccumulate(Dune::Amg::noAccu);
411  coarsenCriterion.setAccumulate(Dune::Amg::atOnceAccu);
412  coarsenCriterion.setSkipIsolated(false);
413 
414 // instantiate the AMG preconditioner
415 #if HAVE_MPI
416  amg_ = new AMG(fineOperator, coarsenCriterion, smootherArgs, *istlComm_);
417 #else
418  amg_ = new AMG(fineOperator, coarsenCriterion, smootherArgs);
419 #endif
420  }
421 
422  const Simulator &simulator_;
423 
424  AMG *amg_;
425 
426 #if HAVE_MPI
427  OwnerOverlapCopyCommunication *istlComm_;
428 #endif
429  OverlappingMatrix *overlappingMatrix_;
430  OverlappingVector *overlappingb_;
431  OverlappingVector *overlappingx_;
432 };
433 
434 } // namespace Linear
435 } // namespace Ewoms
436 
437 #endif
Uses communication on the grid to find the initial seed list of indices.
An ISTL preconditioner that solves the linear system of equations locally on each rank...
An overlap aware block-compressed row storage (BCRS) matrix.
An overlap aware linear operator usable by ISTL.
Provides a linear solver backend using the parallel algebraic multi-grid (AMG) linear solver from DUN...
Definition: parallelamgbackend.hh:60
Base class for all convergence criteria which only defines an virtual API.
Definition: convergencecriterion.hh:51
static void registerParameters()
Definition: parallelamgbackend.hh:145
An overlap aware ISTL scalar product.
SET_INT_PROP(NumericModel, GridGlobalRefinements, 0)
GridManager & gridManager()
Return a reference to the grid manager of simulation.
Definition: simulator.hh:152
Convergence criterion which looks at the weighted absolute value of the residual. ...
Definition: weightedresidreductioncriterion.hh:54
~ParallelAmgBackend()
Definition: parallelamgbackend.hh:142
Definition: cartesianindexmapper.hh:31
NEW_PROP_TAG(Grid)
The type of the DUNE grid.
This file provides the infrastructure to retrieve run-time parameters.
SET_TYPE_PROP(NumericModel, Scalar, double)
Set the default type of scalar values to double.
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:73
Definition: baseauxiliarymodule.hh:35
#define EWOMS_REGISTER_PARAM(TypeTag, ParamType, ParamName, Description)
Register a run-time parameter.
Definition: parametersystem.hh:64
void setStructureMatrix(const Matrix &M)
Set the structure of the linear system of equations to be solved.
Definition: parallelamgbackend.hh:162
Model & model()
Return the physical model used in the simulation.
Definition: simulator.hh:176
Bi-conjugate Gradient Stabilized (BiCG-STAB)
Definition: solvers.hh:623
static void registerParameters()
Register all run-time parameters for the linear solver.
Definition: paralleliterativebackend.hh:207
GridView & gridView()
Return the grid view for which the simulation is done.
Definition: simulator.hh:164
NEW_TYPE_TAG(AuxModule)
ParallelAmgBackend(const Simulator &simulator)
Definition: parallelamgbackend.hh:132
Provides the magic behind the eWoms property system.
An overlap aware block vector.
#define INHERITS_FROM(...)
Syntactic sugar for NEW_TYPE_TAG.
Definition: propertysystem.hh:229
Implements a generic linear solver abstraction.
An overlap aware preconditioner for any ISTL linear solver.
bool solve(const Matrix &M, Vector &x, Vector &b)
Actually solve the linear system of equations.
Definition: parallelamgbackend.hh:173
#define EWOMS_GET_PARAM(TypeTag, ParamType, ParamName)
Retrieve a runtime parameter.
Definition: parametersystem.hh:95