2019-09-09 02:20:08 -05:00
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project ( OPM ) .
OPM is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 2 of the License , or
( at your option ) any later version .
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
Consult the COPYING file in the top - level source directory of this
module for the precise wording of the license and the list of
copyright holders .
*/
/*!
* \ file
* \ copydoc Opm : : Linear : : ParallelAmgBackend
*/
# ifndef EWOMS_PARALLEL_AMG_BACKEND_HH
# define EWOMS_PARALLEL_AMG_BACKEND_HH
2020-05-13 08:24:57 -05:00
# include "linalgproperties.hh"
2019-09-09 02:20:08 -05:00
# include "parallelbasebackend.hh"
# include "bicgstabsolver.hh"
# include "combinedcriterion.hh"
# include "istlsparsematrixadapter.hh"
# include <dune/istl/bcrsmatrix.hh>
# include <dune/istl/paamg/amg.hh>
# include <dune/istl/paamg/pinfo.hh>
# include <dune/istl/owneroverlapcopy.hh>
2023-02-27 02:17:56 -06:00
# include <memory>
# include <tuple>
# include <utility>
2019-09-09 02:20:08 -05:00
2020-06-10 06:07:19 -05:00
namespace Opm : : Linear {
2024-07-01 07:13:14 -05:00
2019-09-09 02:20:08 -05:00
template < class TypeTag >
class ParallelAmgBackend ;
2024-07-01 07:13:14 -05:00
2020-06-10 06:07:19 -05:00
} // namespace Opm::Linear
2019-09-09 02:20:08 -05:00
2020-06-08 10:11:48 -05:00
namespace Opm : : Properties {
2019-09-09 02:20:08 -05:00
2020-06-08 09:41:02 -05:00
// Create new type tags
namespace TTag {
2024-07-01 07:13:14 -05:00
struct ParallelAmgLinearSolver
{ using InheritsFrom = std : : tuple < ParallelBaseLinearSolver > ; } ;
2020-06-08 09:41:02 -05:00
} // end namespace TTag
2019-09-09 02:20:08 -05:00
2020-06-09 03:43:28 -05:00
template < class TypeTag >
2024-07-01 07:13:14 -05:00
struct LinearSolverBackend < TypeTag , TTag : : ParallelAmgLinearSolver >
{ using type = Opm : : Linear : : ParallelAmgBackend < TypeTag > ; } ;
} // namespace Opm::Properties
namespace Opm : : Parameters {
2024-07-01 07:13:14 -05:00
//! The target number of DOFs per processor for the parallel algebraic
//! multi-grid solver
2024-07-05 10:49:51 -05:00
struct AmgCoarsenTarget { static constexpr int value = 5000 ; } ;
2019-09-09 02:20:08 -05:00
2024-07-01 07:13:14 -05:00
}
2019-09-09 02:20:08 -05:00
2024-07-01 07:13:14 -05:00
namespace Opm : : Linear {
2019-09-09 02:20:08 -05:00
/*!
* \ ingroup Linear
*
* \ brief Provides a linear solver backend using the parallel
* algebraic multi - grid ( AMG ) linear solver from DUNE - ISTL .
*/
template < class TypeTag >
class ParallelAmgBackend : public ParallelBaseBackend < TypeTag >
{
2020-06-10 06:49:42 -05:00
using ParentType = ParallelBaseBackend < TypeTag > ;
2019-09-09 02:20:08 -05:00
2020-06-10 06:49:42 -05:00
using Scalar = GetPropType < TypeTag , Properties : : Scalar > ;
using LinearSolverScalar = GetPropType < TypeTag , Properties : : LinearSolverScalar > ;
using Simulator = GetPropType < TypeTag , Properties : : Simulator > ;
using GridView = GetPropType < TypeTag , Properties : : GridView > ;
using Overlap = GetPropType < TypeTag , Properties : : Overlap > ;
using SparseMatrixAdapter = GetPropType < TypeTag , Properties : : SparseMatrixAdapter > ;
2019-09-09 02:20:08 -05:00
2020-06-10 06:49:42 -05:00
using ParallelOperator = typename ParentType : : ParallelOperator ;
using OverlappingVector = typename ParentType : : OverlappingVector ;
using ParallelPreconditioner = typename ParentType : : ParallelPreconditioner ;
using ParallelScalarProduct = typename ParentType : : ParallelScalarProduct ;
2019-09-09 02:20:08 -05:00
2020-06-08 09:41:02 -05:00
static constexpr int numEq = getPropValue < TypeTag , Properties : : NumEq > ( ) ;
2020-06-10 06:49:42 -05:00
using VectorBlock = Dune : : FieldVector < LinearSolverScalar , numEq > ;
using MatrixBlock = typename SparseMatrixAdapter : : MatrixBlock ;
using IstlMatrix = typename SparseMatrixAdapter : : IstlMatrix ;
2019-09-09 02:20:08 -05:00
2020-06-10 06:49:42 -05:00
using Vector = Dune : : BlockVector < VectorBlock > ;
2019-09-09 02:20:08 -05:00
// define the smoother used for the AMG and specify its
// arguments
2020-06-10 06:49:42 -05:00
using SequentialSmoother = Dune : : SeqSOR < IstlMatrix , Vector , Vector > ;
// using SequentialSmoother = Dune::SeqSSOR<IstlMatrix,Vector,Vector>;
// using SequentialSmoother = Dune::SeqJac<IstlMatrix,Vector,Vector>;
// using SequentialSmoother = Dune::SeqILU<IstlMatrix,Vector,Vector>;
2019-09-09 02:20:08 -05:00
# if HAVE_MPI
2020-06-10 06:49:42 -05:00
using OwnerOverlapCopyCommunication = Dune : : OwnerOverlapCopyCommunication < Opm : : Linear : : Index > ;
using FineOperator = Dune : : OverlappingSchwarzOperator < IstlMatrix ,
Vector ,
Vector ,
OwnerOverlapCopyCommunication > ;
using FineScalarProduct = Dune : : OverlappingSchwarzScalarProduct < Vector ,
OwnerOverlapCopyCommunication > ;
using ParallelSmoother = Dune : : BlockPreconditioner < Vector ,
Vector ,
OwnerOverlapCopyCommunication ,
SequentialSmoother > ;
using AMG = Dune : : Amg : : AMG < FineOperator ,
Vector ,
ParallelSmoother ,
OwnerOverlapCopyCommunication > ;
2019-09-09 02:20:08 -05:00
# else
2020-06-10 06:49:42 -05:00
using FineOperator = Dune : : MatrixAdapter < IstlMatrix , Vector , Vector > ;
using FineScalarProduct = Dune : : SeqScalarProduct < Vector > ;
using ParallelSmoother = SequentialSmoother ;
using AMG = Dune : : Amg : : AMG < FineOperator , Vector , ParallelSmoother > ;
2019-09-09 02:20:08 -05:00
# endif
2020-06-10 06:49:42 -05:00
using RawLinearSolver = BiCGStabSolver < ParallelOperator ,
OverlappingVector ,
AMG > ;
2019-09-09 02:20:08 -05:00
static_assert ( std : : is_same < SparseMatrixAdapter , IstlSparseMatrixAdapter < MatrixBlock > > : : value ,
" The ParallelAmgBackend linear solver backend requires the IstlSparseMatrixAdapter " ) ;
public :
ParallelAmgBackend ( const Simulator & simulator )
: ParentType ( simulator )
{ }
static void registerParameters ( )
{
ParentType : : registerParameters ( ) ;
2024-07-05 10:49:51 -05:00
Parameters : : Register < Parameters : : LinearSolverMaxError < Scalar > >
2024-04-04 05:49:01 -05:00
( " The maximum residual error which the linear solver tolerates "
" without giving up " ) ;
2024-07-05 10:49:51 -05:00
Parameters : : Register < Parameters : : AmgCoarsenTarget >
2024-04-04 05:49:01 -05:00
( " The coarsening target for the agglomerations of "
" the AMG preconditioner " ) ;
2019-09-09 02:20:08 -05:00
}
protected :
friend ParentType ;
std : : shared_ptr < AMG > preparePreconditioner_ ( )
{
# if HAVE_MPI
// create and initialize DUNE's OwnerOverlapCopyCommunication
// using the domestic overlap
istlComm_ = std : : make_shared < OwnerOverlapCopyCommunication > ( MPI_COMM_WORLD ) ;
setupAmgIndexSet_ ( this - > overlappingMatrix_ - > overlap ( ) , istlComm_ - > indexSet ( ) ) ;
istlComm_ - > remoteIndices ( ) . template rebuild < false > ( ) ;
# endif
// create the parallel scalar product and the parallel operator
# if HAVE_MPI
fineOperator_ = std : : make_shared < FineOperator > ( * this - > overlappingMatrix_ , * istlComm_ ) ;
# else
fineOperator_ = std : : make_shared < FineOperator > ( * this - > overlappingMatrix_ ) ;
# endif
setupAmg_ ( ) ;
return amg_ ;
}
void cleanupPreconditioner_ ( )
{ /* nothing to do */ }
std : : shared_ptr < RawLinearSolver > prepareSolver_ ( ParallelOperator & parOperator ,
ParallelScalarProduct & parScalarProduct ,
AMG & parPreCond )
{
const auto & gridView = this - > simulator_ . gridView ( ) ;
2020-06-10 06:49:42 -05:00
using CCC = CombinedCriterion < OverlappingVector , decltype ( gridView . comm ( ) ) > ;
2019-09-09 02:20:08 -05:00
2024-07-05 10:49:51 -05:00
Scalar linearSolverTolerance = Parameters : : Get < Parameters : : LinearSolverTolerance < Scalar > > ( ) ;
Scalar linearSolverAbsTolerance = Parameters : : Get < Parameters : : LinearSolverAbsTolerance < Scalar > > ( ) ;
if ( linearSolverAbsTolerance < 0.0 ) {
2019-09-09 02:20:08 -05:00
linearSolverAbsTolerance = this - > simulator_ . model ( ) . newtonMethod ( ) . tolerance ( ) / 100.0 ;
2024-07-05 10:49:51 -05:00
}
2019-09-09 02:20:08 -05:00
convCrit_ . reset ( new CCC ( gridView . comm ( ) ,
/*residualReductionTolerance=*/ linearSolverTolerance ,
/*absoluteResidualTolerance=*/ linearSolverAbsTolerance ,
2024-07-05 10:49:51 -05:00
Parameters : : Get < Parameters : : LinearSolverMaxError < Scalar > > ( ) ) ) ;
2019-09-09 02:20:08 -05:00
auto bicgstabSolver =
std : : make_shared < RawLinearSolver > ( parPreCond , * convCrit_ , parScalarProduct ) ;
int verbosity = 0 ;
if ( parOperator . overlap ( ) . myRank ( ) = = 0 )
2024-07-05 10:49:51 -05:00
verbosity = Parameters : : Get < Parameters : : LinearSolverVerbosity > ( ) ;
2019-09-09 02:20:08 -05:00
bicgstabSolver - > setVerbosity ( verbosity ) ;
2024-07-05 10:49:51 -05:00
bicgstabSolver - > setMaxIterations ( Parameters : : Get < Parameters : : LinearSolverMaxIterations > ( ) ) ;
2019-09-09 02:20:08 -05:00
bicgstabSolver - > setLinearOperator ( & parOperator ) ;
bicgstabSolver - > setRhs ( this - > overlappingb_ ) ;
return bicgstabSolver ;
}
std : : pair < bool , int > runSolver_ ( std : : shared_ptr < RawLinearSolver > solver )
{
bool converged = solver - > apply ( * this - > overlappingx_ ) ;
return std : : make_pair ( converged , int ( solver - > report ( ) . iterations ( ) ) ) ;
}
void cleanupSolver_ ( )
{ /* nothing to do */ }
# if HAVE_MPI
template < class ParallelIndexSet >
void setupAmgIndexSet_ ( const Overlap & overlap , ParallelIndexSet & istlIndices )
{
2020-06-10 06:49:42 -05:00
using GridAttributes = Dune : : OwnerOverlapCopyAttributeSet ;
using GridAttributeSet = Dune : : OwnerOverlapCopyAttributeSet : : AttributeSet ;
2019-09-09 02:20:08 -05:00
// create DUNE's ParallelIndexSet from a domestic overlap
istlIndices . beginResize ( ) ;
for ( Index curIdx = 0 ; static_cast < size_t > ( curIdx ) < overlap . numDomestic ( ) ; + + curIdx ) {
GridAttributeSet gridFlag =
overlap . iAmMasterOf ( curIdx )
? GridAttributes : : owner
: GridAttributes : : copy ;
// an index is used by other processes if it is in the
// domestic or in the foreign overlap.
bool isShared = overlap . isInOverlap ( curIdx ) ;
assert ( curIdx = = overlap . globalToDomestic ( overlap . domesticToGlobal ( curIdx ) ) ) ;
istlIndices . add ( /*globalIdx=*/ overlap . domesticToGlobal ( curIdx ) ,
Dune : : ParallelLocalIndex < GridAttributeSet > ( static_cast < size_t > ( curIdx ) ,
gridFlag ,
isShared ) ) ;
}
istlIndices . endResize ( ) ;
}
# endif
2024-01-25 09:04:41 -06:00
// trailing return type with decltype used for detecting existence of setUseFixedOrder member function by overloading the setUseFixedOrder function
2024-01-18 07:09:12 -06:00
template < typename C >
auto setUseFixedOrder ( C criterion , bool booleanValue ) - > decltype ( criterion . setUseFixedOrder ( booleanValue ) )
{
return criterion . setUseFixedOrder ( booleanValue ) ; // Set flag to ensure that the matrices in the AMG hierarchy are constructed with deterministic indices.
}
template < typename C >
void setUseFixedOrder ( C , . . . )
{
// do nothing, since the function setUseFixedOrder does not exist yet
}
2019-09-09 02:20:08 -05:00
void setupAmg_ ( )
{
if ( amg_ )
amg_ . reset ( ) ;
int verbosity = 0 ;
if ( this - > simulator_ . vanguard ( ) . gridView ( ) . comm ( ) . rank ( ) = = 0 )
2024-07-05 10:49:51 -05:00
verbosity = Parameters : : Get < Parameters : : LinearSolverVerbosity > ( ) ;
2019-09-09 02:20:08 -05:00
2020-06-10 06:49:42 -05:00
using SmootherArgs = typename Dune : : Amg : : SmootherTraits < ParallelSmoother > : : Arguments ;
2019-09-09 02:20:08 -05:00
SmootherArgs smootherArgs ;
smootherArgs . iterations = 1 ;
smootherArgs . relaxationFactor = 1.0 ;
// specify the coarsen criterion:
//
2020-06-10 06:49:42 -05:00
// using CoarsenCriterion =
2019-09-09 02:20:08 -05:00
// Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<IstlMatrix,
// Dune::Amg::FirstDiagonal>>
2020-06-10 06:49:42 -05:00
using CoarsenCriterion = Dune : : Amg : :
CoarsenCriterion < Dune : : Amg : : SymmetricCriterion < IstlMatrix , Dune : : Amg : : FrobeniusNorm > > ;
2024-07-05 10:49:51 -05:00
int coarsenTarget = Parameters : : Get < Parameters : : AmgCoarsenTarget > ( ) ;
2019-09-09 02:20:08 -05:00
CoarsenCriterion coarsenCriterion ( /*maxLevel=*/ 15 , coarsenTarget ) ;
coarsenCriterion . setDefaultValuesAnisotropic ( GridView : : dimension ,
/*aggregateSizePerDim=*/ 3 ) ;
if ( verbosity > 0 )
coarsenCriterion . setDebugLevel ( 1 ) ;
else
coarsenCriterion . setDebugLevel ( 0 ) ; // make the AMG shut up
// reduce the minium coarsen rate (default is 1.2)
coarsenCriterion . setMinCoarsenRate ( 1.05 ) ;
// coarsenCriterion.setAccumulate(Dune::Amg::noAccu);
coarsenCriterion . setAccumulate ( Dune : : Amg : : atOnceAccu ) ;
coarsenCriterion . setSkipIsolated ( false ) ;
2024-01-18 07:09:12 -06:00
setUseFixedOrder ( coarsenCriterion , true ) ; // If possible, set flag to ensure that the matrices in the AMG hierarchy are constructed with deterministic indices.
2019-09-09 02:20:08 -05:00
// instantiate the AMG preconditioner
# if HAVE_MPI
amg_ = std : : make_shared < AMG > ( * fineOperator_ , coarsenCriterion , smootherArgs , * istlComm_ ) ;
# else
amg_ = std : : make_shared < AMG > ( * fineOperator_ , coarsenCriterion , smootherArgs ) ;
# endif
}
std : : unique_ptr < ConvergenceCriterion < OverlappingVector > > convCrit_ ;
std : : shared_ptr < FineOperator > fineOperator_ ;
std : : shared_ptr < AMG > amg_ ;
# if HAVE_MPI
std : : shared_ptr < OwnerOverlapCopyCommunication > istlComm_ ;
# endif
} ;
2024-07-01 07:13:14 -05:00
} // namespace Opm::Linear
2019-09-09 02:20:08 -05:00
# endif