Changes to make CPR able to use general indexing.

This commit is contained in:
hnil 2019-03-15 11:27:38 +01:00 committed by Atgeirr Flø Rasmussen
parent 9af17dcc8c
commit 31f4c01938
4 changed files with 78 additions and 57 deletions

View File

@ -42,6 +42,27 @@ class UnSymmetricCriterion;
} }
} }
namespace Opm
{
namespace Amg
{
template<int Row, int Column>
class Element
{
public:
enum { /* @brief We preserve the sign.*/
is_sign_preserving = true
};
template<class M>
typename M::field_type operator()(const M& m) const
{
return m[Row][Column];
}
};
} // namespace Amg
} // namespace Opm
namespace Dune namespace Dune
{ {
@ -99,12 +120,12 @@ Dune::OverlappingSchwarzOperator<M,X,Y,T> createOperator(const Dune::Overlapping
//! Sedimentary Basin Simulations, 2003. //! Sedimentary Basin Simulations, 2003.
//! \param op The operator that stems from the discretization. //! \param op The operator that stems from the discretization.
//! \param comm The communication objecte describing the data distribution. //! \param comm The communication objecte describing the data distribution.
//! \param pressureIndex The index of the pressure in the matrix block //! \param pressureEqnIndex The index of the pressure in the matrix block
//! \retun A pair of the scaled matrix and the associated operator- //! \retun A pair of the scaled matrix and the associated operator-
template<class Operator, class Communication, class Vector> template<class Operator, class Communication, class Vector>
std::tuple<std::unique_ptr<typename Operator::matrix_type>, Operator> std::tuple<std::unique_ptr<typename Operator::matrix_type>, Operator>
scaleMatrixDRS(const Operator& op, const Communication& comm, scaleMatrixDRS(const Operator& op, const Communication& comm,
std::size_t pressureIndex, const Vector& weights, const Opm::CPRParameter& param) std::size_t pressureEqnIndex, const Vector& weights, const Opm::CPRParameter& param)
{ {
using Matrix = typename Operator::matrix_type; using Matrix = typename Operator::matrix_type;
using Block = typename Matrix::block_type; using Block = typename Matrix::block_type;
@ -117,7 +138,7 @@ scaleMatrixDRS(const Operator& op, const Communication& comm,
const auto endj = (*i).end(); const auto endj = (*i).end();
for (auto j = (*i).begin(); j != endj; ++j) { for (auto j = (*i).begin(); j != endj; ++j) {
Block& block = *j; Block& block = *j;
BlockVector& bvec = block[pressureIndex]; BlockVector& bvec = block[pressureEqnIndex];
// should introduce limits which also change the weights // should introduce limits which also change the weights
block.mtv(bw, bvec); block.mtv(bw, bvec);
} }
@ -131,16 +152,16 @@ scaleMatrixDRS(const Operator& op, const Communication& comm,
//! See section 3.2.3 of Scheichl, Masson: Decoupling and Block Preconditioning for //! See section 3.2.3 of Scheichl, Masson: Decoupling and Block Preconditioning for
//! Sedimentary Basin Simulations, 2003. //! Sedimentary Basin Simulations, 2003.
//! \param vector The vector to scale //! \param vector The vector to scale
//! \param pressureIndex The index of the pressure in the matrix block //! \param pressureEqnIndex The index of the pressure in the matrix block
template<class Vector> template<class Vector>
void scaleVectorDRS(Vector& vector, std::size_t pressureIndex, const Opm::CPRParameter& param, const Vector& weights) void scaleVectorDRS(Vector& vector, std::size_t pressureEqnIndex, const Opm::CPRParameter& param, const Vector& weights)
{ {
using Block = typename Vector::block_type; using Block = typename Vector::block_type;
if (param.cpr_use_drs_) { if (param.cpr_use_drs_) {
for (std::size_t j = 0; j < vector.size(); ++j) { for (std::size_t j = 0; j < vector.size(); ++j) {
Block& block = vector[j]; Block& block = vector[j];
const Block& bw = weights[j]; const Block& bw = weights[j];
block[pressureIndex] = bw.dot(block); block[pressureEqnIndex] = bw.dot(block);
} }
} }
} }
@ -289,23 +310,23 @@ struct ScalarType<Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Du
using value = Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Dune::BCRSMatrix<typename ScalarType<B>::value>, Dune::Amg::FirstDiagonal> >; using value = Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Dune::BCRSMatrix<typename ScalarType<B>::value>, Dune::Amg::FirstDiagonal> >;
}; };
template<class C, std::size_t COMPONENT_INDEX> template<class C, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
struct OneComponentCriterionType struct OneComponentCriterionType
{}; {};
template<class B, class N, std::size_t COMPONENT_INDEX> template<class B, class N, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
struct OneComponentCriterionType<Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<Dune::BCRSMatrix<B>,N> >,COMPONENT_INDEX> struct OneComponentCriterionType<Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<Dune::BCRSMatrix<B>,N> >, COMPONENT_INDEX, VARIABLE_INDEX>
{ {
using value = Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<Dune::BCRSMatrix<B>, Dune::Amg::Diagonal<COMPONENT_INDEX> > >; using value = Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<Dune::BCRSMatrix<B>, Opm::Amg::Element<COMPONENT_INDEX, VARIABLE_INDEX> > >;
}; };
template<class B, class N, std::size_t COMPONENT_INDEX> template<class B, class N, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
struct OneComponentCriterionType<Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Dune::BCRSMatrix<B>,N> >,COMPONENT_INDEX> struct OneComponentCriterionType<Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Dune::BCRSMatrix<B>,N> >, COMPONENT_INDEX, VARIABLE_INDEX>
{ {
using value = Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Dune::BCRSMatrix<B>, Dune::Amg::Diagonal<COMPONENT_INDEX> > >; using value = Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Dune::BCRSMatrix<B>, Opm::Amg::Element<COMPONENT_INDEX, VARIABLE_INDEX> > >;
}; };
template<class Operator, class Criterion, class Communication, std::size_t COMPONENT_INDEX> template<class Operator, class Criterion, class Communication, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
class OneComponentAggregationLevelTransferPolicy; class OneComponentAggregationLevelTransferPolicy;
@ -674,7 +695,7 @@ void buildCoarseSparseMatrix(M& coarseMatrix, G& fineGraph, const V& visitedMap,
* @tparam Criterion The criterion that describes the aggregation procedure. * @tparam Criterion The criterion that describes the aggregation procedure.
* @tparam Communication The class that describes the communication pattern. * @tparam Communication The class that describes the communication pattern.
*/ */
template<class Operator, class Criterion, class Communication, std::size_t COMPONENT_INDEX> template<class Operator, class Criterion, class Communication, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
class OneComponentAggregationLevelTransferPolicy class OneComponentAggregationLevelTransferPolicy
: public Dune::Amg::LevelTransferPolicy<Operator, typename Detail::ScalarType<Operator>::value> : public Dune::Amg::LevelTransferPolicy<Operator, typename Detail::ScalarType<Operator>::value>
{ {
@ -785,7 +806,7 @@ public:
for ( auto col = row.begin(), cend = row.end(); col != cend; ++col, ++coarseCol ) for ( auto col = row.begin(), cend = row.end(); col != cend; ++col, ++coarseCol )
{ {
assert( col.index() == coarseCol.index() ); assert( col.index() == coarseCol.index() );
*coarseCol = (*col)[COMPONENT_INDEX][COMPONENT_INDEX]; *coarseCol = (*col)[COMPONENT_INDEX][VARIABLE_INDEX];
} }
++coarseRow; ++coarseRow;
} }
@ -815,7 +836,7 @@ public:
const auto& j = (*aggregatesMap_)[entry.index()]; const auto& j = (*aggregatesMap_)[entry.index()];
if ( j != AggregatesMap::ISOLATED ) if ( j != AggregatesMap::ISOLATED )
{ {
(*coarseLevelMatrix_)[i][j] += (*entry)[COMPONENT_INDEX][COMPONENT_INDEX]; (*coarseLevelMatrix_)[i][j] += (*entry)[COMPONENT_INDEX][VARIABLE_INDEX];
} }
} }
} }
@ -911,9 +932,10 @@ private:
* \tparam C The type of coarsening criterion to use. * \tparam C The type of coarsening criterion to use.
* \tparam P The type of the class describing the parallelization. * \tparam P The type of the class describing the parallelization.
* \tparam COMPONENT_INDEX The index of the component to use for coarsening (usually the pressure). * \tparam COMPONENT_INDEX The index of the component to use for coarsening (usually the pressure).
* \tparam VARIABLE_INDEX The index of the variable to use for coarsening (usually the pressure).
*/ */
template<typename O, typename S, typename C, template<typename O, typename S, typename C,
typename P, std::size_t COMPONENT_INDEX> typename P, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
class BlackoilAmg class BlackoilAmg
: public Dune::Preconditioner<typename O::domain_type, typename O::range_type> : public Dune::Preconditioner<typename O::domain_type, typename O::range_type>
{ {
@ -934,13 +956,14 @@ protected:
using CoarseOperator = typename Detail::ScalarType<Operator>::value; using CoarseOperator = typename Detail::ScalarType<Operator>::value;
using CoarseSmoother = typename Detail::ScalarType<Smoother>::value; using CoarseSmoother = typename Detail::ScalarType<Smoother>::value;
using FineCriterion = using FineCriterion =
typename Detail::OneComponentCriterionType<Criterion,COMPONENT_INDEX>::value; typename Detail::OneComponentCriterionType<Criterion, COMPONENT_INDEX, VARIABLE_INDEX>::value;
using CoarseCriterion = typename Detail::ScalarType<Criterion>::value; using CoarseCriterion = typename Detail::ScalarType<Criterion>::value;
using LevelTransferPolicy = using LevelTransferPolicy =
OneComponentAggregationLevelTransferPolicy<Operator, OneComponentAggregationLevelTransferPolicy<Operator,
FineCriterion, FineCriterion,
Communication, Communication,
COMPONENT_INDEX>; COMPONENT_INDEX,
VARIABLE_INDEX>;
using CoarseSolverPolicy = using CoarseSolverPolicy =
Detail::OneStepAMGCoarseSolverPolicy<CoarseOperator, Detail::OneStepAMGCoarseSolverPolicy<CoarseOperator,
CoarseSmoother, CoarseSmoother,
@ -1028,7 +1051,7 @@ namespace ISTLUtility
/// \tparam C The type of the coarsening criterion to use. /// \tparam C The type of the coarsening criterion to use.
/// \tparam index The pressure index. /// \tparam index The pressure index.
//// ////
template<class M, class X, class Y, class P, class C, std::size_t index> template<class M, class X, class Y, class P, class C, std::size_t pressureEqnIndex, std::size_t pressureVarIndex>
struct BlackoilAmgSelector struct BlackoilAmgSelector
{ {
using Criterion = C; using Criterion = C;
@ -1036,7 +1059,7 @@ struct BlackoilAmgSelector
using ParallelInformation = typename Selector::ParallelInformation; using ParallelInformation = typename Selector::ParallelInformation;
using Operator = typename Selector::Operator; using Operator = typename Selector::Operator;
using Smoother = typename Selector::EllipticPreconditioner; using Smoother = typename Selector::EllipticPreconditioner;
using AMG = BlackoilAmg<Operator,Smoother,Criterion,ParallelInformation,index>; using AMG = BlackoilAmg<Operator, Smoother, Criterion, ParallelInformation, pressureEqnIndex, pressureVarIndex>;
}; };
} // end namespace ISTLUtility } // end namespace ISTLUtility
} // end namespace Opm } // end namespace Opm

View File

@ -55,9 +55,15 @@ namespace Opm
{ {
template<typename O, typename S, typename C, template<typename O, typename S, typename C,
typename P, std::size_t COMPONENT_INDEX> typename P, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
class BlackoilAmg; class BlackoilAmg;
namespace Amg
{
template<int Row, int Column>
class Element;
}
namespace ISTLUtility namespace ISTLUtility
{ {
@ -183,14 +189,14 @@ createEllipticPreconditionerPointer(const M& Ae, double relax,
return EllipticPreconditionerPointer(new ParallelPreconditioner(Ae, comm, relax, milu)); return EllipticPreconditionerPointer(new ParallelPreconditioner(Ae, comm, relax, milu));
} }
template < class C, class Op, class P, class S, std::size_t index, class Vector> template < class C, class Op, class P, class S, std::size_t PressureEqnIndex, std::size_t PressureVarIndex, class Vector>
inline void inline void
createAMGPreconditionerPointer(Op& opA, const double relax, const P& comm, createAMGPreconditionerPointer(Op& opA, const double relax, const P& comm,
std::unique_ptr< BlackoilAmg<Op,S,C,P,index> >& amgPtr, std::unique_ptr< BlackoilAmg<Op,S,C,P,PressureEqnIndex,PressureVarIndex> >& amgPtr,
const CPRParameter& params, const CPRParameter& params,
const Vector& weights) const Vector& weights)
{ {
using AMG = BlackoilAmg<Op,S,C,P,index>; using AMG = BlackoilAmg<Op,S,C,P,PressureEqnIndex,PressureVarIndex>;
const int verbosity = ( params.cpr_solver_verbose_ && comm.communicator().rank() == 0 ) ? 1 : 0; const int verbosity = ( params.cpr_solver_verbose_ && comm.communicator().rank() == 0 ) ? 1 : 0;
// TODO: revise choice of parameters // TODO: revise choice of parameters
@ -242,7 +248,7 @@ createAMGPreconditionerPointer(Op& opA, const double relax, const MILU_VARIANT m
/// \param relax The relaxation parameter for ILU0. /// \param relax The relaxation parameter for ILU0.
/// \param comm The object describing the parallelization information and communication. /// \param comm The object describing the parallelization information and communication.
// \param amgPtr The unique_ptr to be filled (return) // \param amgPtr The unique_ptr to be filled (return)
template < int pressureIndex=0, class Op, class P, class AMG > template < int PressureEqnIndex, int PressureVarIndex, class Op, class P, class AMG >
inline void inline void
createAMGPreconditionerPointer( Op& opA, const double relax, const MILU_VARIANT milu, const P& comm, std::unique_ptr< AMG >& amgPtr ) createAMGPreconditionerPointer( Op& opA, const double relax, const MILU_VARIANT milu, const P& comm, std::unique_ptr< AMG >& amgPtr )
{ {
@ -250,7 +256,7 @@ createAMGPreconditionerPointer( Op& opA, const double relax, const MILU_VARIANT
typedef typename Op::matrix_type M; typedef typename Op::matrix_type M;
// The coupling metric used in the AMG // The coupling metric used in the AMG
typedef Dune::Amg::Diagonal<pressureIndex> CouplingMetric; typedef Opm::Amg::Element<PressureEqnIndex, PressureVarIndex> CouplingMetric;
// The coupling criterion used in the AMG // The coupling criterion used in the AMG
typedef Dune::Amg::SymmetricCriterion<M, CouplingMetric> CritBase; typedef Dune::Amg::SymmetricCriterion<M, CouplingMetric> CritBase;

View File

@ -1,5 +1,6 @@
/* /*
Copyright 2016 IRIS AS Copyright 2016 IRIS AS
Copyright 2019 Equinor ASA
This file is part of the Open Porous Media project (OPM). This file is part of the Open Porous Media project (OPM).
@ -31,6 +32,7 @@
#include <opm/common/Exceptions.hpp> #include <opm/common/Exceptions.hpp>
#include <opm/core/linalg/ParallelIstlInformation.hpp> #include <opm/core/linalg/ParallelIstlInformation.hpp>
#include <opm/common/utility/platform_dependent/disable_warnings.h> #include <opm/common/utility/platform_dependent/disable_warnings.h>
#include <opm/material/fluidsystems/BlackOilDefaultIndexTraits.hpp>
#include <ewoms/common/parametersystem.hh> #include <ewoms/common/parametersystem.hh>
#include <ewoms/common/propertysystem.hh> #include <ewoms/common/propertysystem.hh>
@ -162,11 +164,6 @@ protected:
/// solving the reduced system (after eliminating well variables) /// solving the reduced system (after eliminating well variables)
/// as a block-structured matrix (one block for all cell variables) for a fixed /// as a block-structured matrix (one block for all cell variables) for a fixed
/// number of cell variables np . /// number of cell variables np .
/// \tparam MatrixBlockType The type of the matrix block used.
/// \tparam VectorBlockType The type of the vector block used.
/// \tparam pressureIndex The index of the pressure component in the vector
/// vector block. It is used to guide the AMG coarsening.
/// Default is zero.
template <class TypeTag> template <class TypeTag>
class ISTLSolverEbos class ISTLSolverEbos
{ {
@ -185,7 +182,9 @@ protected:
typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager; typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager;
typedef typename GridView::template Codim<0>::Entity Element; typedef typename GridView::template Codim<0>::Entity Element;
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
enum { pressureIndex = Indices::pressureSwitchIdx }; // Due to miscibility oil <-> gas the water eqn is the one we can replace with a pressure equation.
enum { pressureEqnIndex = BlackOilDefaultIndexTraits::waterCompIdx };
enum { pressureVarIndex = Indices::pressureSwitchIdx };
static const int numEq = Indices::numEq; static const int numEq = Indices::numEq;
public: public:
@ -236,7 +235,7 @@ protected:
weights_ = getSimpleWeights(bvec); weights_ = getSimpleWeights(bvec);
} else if (parameters_.system_strategy_ == "original") { } else if (parameters_.system_strategy_ == "original") {
BlockVector bvec(0.0); BlockVector bvec(0.0);
bvec[pressureIndex] = 1; bvec[pressureEqnIndex] = 1;
weights_ = getSimpleWeights(bvec); weights_ = getSimpleWeights(bvec);
} else { } else {
form_cpr = false; form_cpr = false;
@ -370,11 +369,11 @@ protected:
if ( parameters_.use_cpr_ ) if ( parameters_.use_cpr_ )
{ {
using Matrix = typename MatrixOperator::matrix_type; using Matrix = typename MatrixOperator::matrix_type;
using CouplingMetric = Dune::Amg::Diagonal<pressureIndex>; using CouplingMetric = Opm::Amg::Element<pressureEqnIndex, pressureVarIndex>;
using CritBase = Dune::Amg::SymmetricCriterion<Matrix, CouplingMetric>; using CritBase = Dune::Amg::SymmetricCriterion<Matrix, CouplingMetric>;
using Criterion = Dune::Amg::CoarsenCriterion<CritBase>; using Criterion = Dune::Amg::CoarsenCriterion<CritBase>;
using AMG = typename ISTLUtility using AMG = typename ISTLUtility
::BlackoilAmgSelector< Matrix, Vector, Vector,POrComm, Criterion, pressureIndex >::AMG; ::BlackoilAmgSelector< Matrix, Vector, Vector,POrComm, Criterion, pressureEqnIndex, pressureVarIndex >::AMG;
std::unique_ptr< AMG > amg; std::unique_ptr< AMG > amg;
// Construct preconditioner. // Construct preconditioner.
@ -458,7 +457,7 @@ protected:
void void
constructAMGPrecond(LinearOperator& /* linearOperator */, const POrComm& comm, std::unique_ptr< AMG >& amg, std::unique_ptr< MatrixOperator >& opA, const double relax, const MILU_VARIANT milu) const constructAMGPrecond(LinearOperator& /* linearOperator */, const POrComm& comm, std::unique_ptr< AMG >& amg, std::unique_ptr< MatrixOperator >& opA, const double relax, const MILU_VARIANT milu) const
{ {
ISTLUtility::template createAMGPreconditionerPointer<pressureIndex>( *opA, relax, milu, comm, amg ); ISTLUtility::template createAMGPreconditionerPointer<pressureEqnIndex, pressureVarIndex>( *opA, relax, milu, comm, amg );
} }
@ -636,7 +635,7 @@ protected:
{ {
Vector weights(rhs_->size()); Vector weights(rhs_->size());
BlockVector rhs(0.0); BlockVector rhs(0.0);
rhs[pressureIndex] = 1.0; rhs[pressureVarIndex] = 1.0;
int index = 0; int index = 0;
ElementContext elemCtx(simulator_); ElementContext elemCtx(simulator_);
const auto& vanguard = simulator_.vanguard(); const auto& vanguard = simulator_.vanguard();
@ -657,7 +656,7 @@ protected:
for (int ii = 0; ii < numEq; ++ii) { for (int ii = 0; ii < numEq; ++ii) {
for (int jj = 0; jj < numEq; ++jj) { for (int jj = 0; jj < numEq; ++jj) {
block[ii][jj] = storage[ii].derivative(jj)/storage_scale; block[ii][jj] = storage[ii].derivative(jj)/storage_scale;
if (jj == 0) { if (jj == pressureVarIndex) {
block[ii][jj] *= pressure_scale; block[ii][jj] *= pressure_scale;
} }
} }
@ -720,7 +719,7 @@ protected:
Matrix& A = *matrix_; Matrix& A = *matrix_;
Vector weights(rhs_->size()); Vector weights(rhs_->size());
BlockVector rhs(0.0); BlockVector rhs(0.0);
rhs[pressureIndex] = 1; rhs[pressureVarIndex] = 1;
const auto endi = A.end(); const auto endi = A.end();
for (auto i = A.begin(); i!=endi; ++i) { for (auto i = A.begin(); i!=endi; ++i) {
const auto endj = (*i).end(); const auto endj = (*i).end();
@ -761,27 +760,20 @@ protected:
const auto endj = (*i).end(); const auto endj = (*i).end();
for (auto j = (*i).begin(); j != endj; ++j) { for (auto j = (*i).begin(); j != endj; ++j) {
// assume it is something on all rows // assume it is something on all rows
// the blew logic depend on pressureIndex=0
Block& block = (*j); Block& block = (*j);
for ( std::size_t ii = 0; ii < block.rows; ii++ ) { BlockVector neweq(0.0);
if ( ii == 0 ) { for (std::size_t ii = 0; ii < block.rows; ii++) {
for (std::size_t jj = 0; jj < block.cols; jj++) { for (std::size_t jj = 0; jj < block.cols; jj++) {
block[0][jj] *= bweights[ii]; neweq[jj] += bweights[ii]*block[ii][jj];
}
} else {
for (std::size_t jj = 0; jj < block.cols; jj++) {
block[0][jj] += bweights[ii]*block[ii][jj];
}
} }
} }
block[pressureEqnIndex] = neweq;
} }
BlockVector newrhs(0.0);
for (std::size_t ii = 0; ii < brhs.size(); ii++) { for (std::size_t ii = 0; ii < brhs.size(); ii++) {
if ( ii == 0 ){ newrhs += bweights[ii]*brhs[ii];
brhs[0] *= bweights[ii];
} else {
brhs[0] += bweights[ii]*brhs[ii];
}
} }
brhs = newrhs;
} }
} }

View File

@ -303,7 +303,7 @@ void runBlackoilAmgLaplace()
smootherArgs.iterations = 1; smootherArgs.iterations = 1;
Opm::CPRParameter param; Opm::CPRParameter param;
Opm::BlackoilAmg<Operator,ParSmoother,Criterion,Communication,0> amg(param, Opm::BlackoilAmg<Operator,ParSmoother,Criterion,Communication,0,0> amg(param,
{}, {},
fop, criterion, fop, criterion,
smootherArgs, smootherArgs,