Add flexible solver and preconditioner infrastructure.

Also use it in flow_blackoil_dunecpr.cpp. Adds new command-line parameter,
--linear-solver-configuration-json-file, to read linear solver config from
JSON-format file at runtime.
This commit is contained in:
Halvor Møll Nilsen 2019-05-20 13:23:57 +02:00 committed by Atgeirr Flø Rasmussen
parent 2cc22f99cb
commit ec498086a6
18 changed files with 1435 additions and 5 deletions

20
.clang-format Normal file
View File

@ -0,0 +1,20 @@
{
BasedOnStyle: WebKit,
AlignAfterOpenBracket: AlwaysBreak,
AlignConsecutiveAssignments: false,
AlignConsecutiveDeclarations: false,
AlignAfterOpenBracket: Align,
AllowShortBlocksOnASingleLine: false,
AllowShortFunctionsOnASingleLine: None,
AlwaysBreakAfterReturnType: TopLevelDefinitions,
AlwaysBreakTemplateDeclarations: Yes,
BinPackArguments: false,
BinPackParameters: false,
BreakBeforeBraces: Linux,
BreakConstructorInitializers: BeforeComma,
ColumnLimit: 120,
Cpp11BracedListStyle: true,
FixNamespaceComments: true,
MaxEmptyLinesToKeep: 5,
NamespaceIndentation: Inner,
}

View File

@ -37,6 +37,7 @@ list (APPEND MAIN_SOURCE_FILES
opm/core/wells/well_controls.c
opm/core/wells/wells.c
opm/simulators/linalg/ExtractParallelGridInformationToISTL.cpp
opm/simulators/linalg/setupPropertyTree.cpp
opm/simulators/timestepping/TimeStepControl.cpp
opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp
opm/simulators/timestepping/SimulatorTimer.cpp
@ -55,6 +56,7 @@ list (APPEND TEST_SOURCE_FILES
tests/test_ecl_output.cc
tests/test_blackoil_amg.cpp
tests/test_convergencereport.cpp
tests/test_flexiblesolver.cpp
tests/test_graphcoloring.cpp
tests/test_vfpproperties.cpp
tests/test_milu.cpp
@ -110,6 +112,9 @@ list (APPEND TEST_DATA_FILES
tests/relpermDiagnostics.DATA
tests/norne_pvt.data
tests/wells_no_perforation.data
tests/matr33.txt
tests/rhs3.txt
tests/options_flexiblesolver.json
)
@ -155,14 +160,23 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/linalg/twolevelmethodcpr.hh
opm/simulators/linalg/CPRPreconditioner.hpp
opm/simulators/linalg/ExtractParallelGridInformationToISTL.hpp
opm/simulators/linalg/FlexibleSolver.hpp
opm/simulators/linalg/FlowLinearSolverParameters.hpp
opm/simulators/linalg/GetQuasiImpesWeights.hpp
opm/simulators/linalg/GraphColoring.hpp
opm/simulators/linalg/ISTLSolverEbos.hpp
opm/simulators/linalg/ISTLSolverEbosCpr.hpp
opm/simulators/linalg/ISTLSolverEbosFlexible.hpp
opm/simulators/linalg/MatrixBlock.hpp
opm/simulators/linalg/MatrixMarketUtils.hpp
opm/simulators/linalg/OwningTwolevelPreconditioner.hpp
opm/simulators/linalg/ParallelOverlappingILU0.hpp
opm/simulators/linalg/ParallelRestrictedAdditiveSchwarz.hpp
opm/simulators/linalg/ParallelIstlInformation.hpp
opm/simulators/linalg/PressureSolverPolicy.hpp
opm/simulators/linalg/PressureTransferPolicy.hpp
opm/simulators/linalg/makePreconditioner.hpp
opm/simulators/linalg/setupPropertyTree.hpp
opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp
opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp
opm/simulators/timestepping/ConvergenceReport.hpp

View File

@ -1,5 +1,5 @@
/*
Copyright 2013, 2014, 2015 SINTEF ICT, Applied Mathematics.
Copyright 2013, 2014, 2015, 2019 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services
Copyright 2015, 2017 IRIS AS
@ -21,7 +21,7 @@
#include "config.h"
#include "flow/flow_tag.hpp"
//#include <opm/linearsolvers/amgclsolverbackend.hh>
#include <opm/simulators/linalg/ISTLSolverEbosCpr.hpp>
#include <opm/simulators/linalg/ISTLSolverEbosFlexible.hpp>
//#include <ewoms/linear/superlubackend.hh>
BEGIN_PROPERTIES
@ -48,8 +48,8 @@ SET_PROP(EclFlowProblemSimple, FluidState)
SET_BOOL_PROP(EclFlowProblemSimple,MatrixAddWellContributions,true);
SET_INT_PROP(EclFlowProblemSimple,LinearSolverVerbosity,0);
SET_SCALAR_PROP(EclFlowProblemSimple, LinearSolverReduction, 1e-4);
SET_INT_PROP(EclFlowProblemSimple, LinearSolverMaxIter, 20);
SET_SCALAR_PROP(EclFlowProblemSimple, LinearSolverReduction, 1e-2);
SET_INT_PROP(EclFlowProblemSimple, LinearSolverMaxIter, 100);
SET_BOOL_PROP(EclFlowProblemSimple, UseAmg, true);//probably not used
SET_BOOL_PROP(EclFlowProblemSimple, UseCpr, true);
SET_INT_PROP(EclFlowProblemSimple, CprMaxEllIter, 1);
@ -79,7 +79,7 @@ namespace Ewoms {
//SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Ewoms::Linear::ParallelBiCGStabSolverBackend<TypeTag>);//not work
//SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Ewoms::Linear::SuperLUBackend<TypeTag>)//not work
//SET_TAG_PROP(EclFlowProblem, FluidState, Opm::BlackOilFluidState);
SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbosCpr<TypeTag>);
SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbosFlexible<TypeTag>);
SET_BOOL_PROP(EclFlowProblemSimple, EnableStorageCache, true);
SET_BOOL_PROP(EclFlowProblemSimple, EnableIntensiveQuantityCache, true);

View File

@ -0,0 +1,115 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_FLEXIBLE_SOLVER_HEADER_INCLUDED
#define OPM_FLEXIBLE_SOLVER_HEADER_INCLUDED
#include <opm/simulators/linalg/makePreconditioner.hpp>
#include <dune/common/fmatrix.hh>
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/solvers.hh>
#include <dune/istl/umfpack.hh>
#include <boost/property_tree/ptree.hpp>
namespace Dune
{
template <class MatrixTypeT, class VectorTypeT>
class FlexibleSolver : Dune::InverseOperator<VectorTypeT, VectorTypeT>
{
public:
using MatrixType = MatrixTypeT;
using VectorType = VectorTypeT;
FlexibleSolver(const boost::property_tree::ptree& prm, const MatrixType& matrix)
{
makeSolver(prm, matrix);
}
virtual void apply(VectorType& x, VectorType& rhs, Dune::InverseOperatorResult& res) override
{
linsolver_->apply(x, rhs, res);
}
virtual void apply(VectorType& x, VectorType& rhs, double reduction, Dune::InverseOperatorResult& res) override
{
linsolver_->apply(x, rhs, reduction, res);
}
virtual Dune::SolverCategory::Category category() const override
{
return Dune::SolverCategory::sequential;
}
private:
void makeSolver(const boost::property_tree::ptree& prm, const MatrixType& matrix)
{
const double tol = prm.get<double>("tol");
const int maxiter = prm.get<int>("maxiter");
linearoperator_.reset(new Dune::MatrixAdapter<MatrixType, VectorType, VectorType>(matrix));
preconditioner_ = Dune::makePreconditioner<MatrixType, VectorType>(*linearoperator_, prm);
int verbosity = prm.get<int>("verbosity");
std::string solver_type = prm.get<std::string>("solver");
if (solver_type == "bicgstab") {
linsolver_.reset(new Dune::BiCGSTABSolver<VectorType>(*linearoperator_,
*preconditioner_,
tol, // desired residual reduction factor
maxiter, // maximum number of iterations
verbosity));
} else if (solver_type == "loopsolver") {
linsolver_.reset(new Dune::LoopSolver<VectorType>(*linearoperator_,
*preconditioner_,
tol, // desired residual reduction factor
maxiter, // maximum number of iterations
verbosity));
} else if (solver_type == "gmres") {
int restart = prm.get<int>("restart");
linsolver_.reset(new Dune::RestartedGMResSolver<VectorType>(*linearoperator_,
*preconditioner_,
tol,
restart, // desired residual reduction factor
maxiter, // maximum number of iterations
verbosity));
#if HAVE_SUITESPARSE_UMFPACK
} else if (solver_type == "umfpack") {
bool dummy = false;
linsolver_.reset(new Dune::UMFPack<MatrixType>(linearoperator_->getmat(), verbosity, dummy));
#endif
} else {
std::string msg("Solver not known ");
msg += solver_type;
throw std::runtime_error(msg);
}
}
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>> preconditioner_;
std::shared_ptr<Dune::MatrixAdapter<MatrixType, VectorType, VectorType>> linearoperator_;
std::shared_ptr<Dune::InverseOperator<VectorType, VectorType>> linsolver_;
};
} // namespace Dune
#endif // OPM_FLEXIBLE_SOLVER_HEADER_INCLUDED

View File

@ -66,6 +66,7 @@ NEW_PROP_TAG(CprUseDrs);
NEW_PROP_TAG(CprMaxEllIter);
NEW_PROP_TAG(CprEllSolvetype);
NEW_PROP_TAG(CprReuseSetup);
NEW_PROP_TAG(LinearSolverConfigurationJsonFile);
SET_SCALAR_PROP(FlowIstlSolverParams, LinearSolverReduction, 1e-2);
SET_SCALAR_PROP(FlowIstlSolverParams, IluRelaxation, 0.9);
@ -90,6 +91,7 @@ SET_BOOL_PROP(FlowIstlSolverParams, CprUseDrs, false);
SET_INT_PROP(FlowIstlSolverParams, CprMaxEllIter, 20);
SET_INT_PROP(FlowIstlSolverParams, CprEllSolvetype, 0);
SET_INT_PROP(FlowIstlSolverParams, CprReuseSetup, 0);
SET_STRING_PROP(FlowIstlSolverParams, LinearSolverConfigurationJsonFile, "none");
@ -160,6 +162,7 @@ namespace Opm
bool use_cpr_;
std::string system_strategy_;
bool scale_linear_system_;
std::string linear_solver_configuration_json_file_;
template <class TypeTag>
void init()
@ -186,6 +189,7 @@ namespace Opm
cpr_max_ell_iter_ = EWOMS_GET_PARAM(TypeTag, int, CprMaxEllIter);
cpr_ell_solvetype_ = EWOMS_GET_PARAM(TypeTag, int, CprEllSolvetype);
cpr_reuse_setup_ = EWOMS_GET_PARAM(TypeTag, int, CprReuseSetup);
linear_solver_configuration_json_file_ = EWOMS_GET_PARAM(TypeTag, std::string, LinearSolverConfigurationJsonFile);
}
template <class TypeTag>
@ -212,6 +216,7 @@ namespace Opm
EWOMS_REGISTER_PARAM(TypeTag, int, CprMaxEllIter, "MaxIterations of the elliptic pressure part of the cpr solver");
EWOMS_REGISTER_PARAM(TypeTag, int, CprEllSolvetype, "Solver type of elliptic pressure solve (0: bicgstab, 1: cg, 2: only amg preconditioner)");
EWOMS_REGISTER_PARAM(TypeTag, int, CprReuseSetup, "Reuse Amg Setup");
EWOMS_REGISTER_PARAM(TypeTag, std::string, LinearSolverConfigurationJsonFile, "Filename of JSON configuration for flexible linear solver system.");
}
FlowLinearSolverParameters() { reset(); }

View File

@ -0,0 +1,125 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_ISTLSOLVEREBOSFLEXIBLE_HEADER_INCLUDED
#define OPM_ISTLSOLVEREBOSFLEXIBLE_HEADER_INCLUDED
#include <ewoms/linear/matrixblock.hh>
#include <opm/simulators/linalg/FlexibleSolver.hpp>
#include <opm/simulators/linalg/setupPropertyTree.hpp>
#include <memory>
#include <utility>
BEGIN_PROPERTIES
NEW_TYPE_TAG(FlowIstlSolverFlexible, INHERITS_FROM(FlowIstlSolverParams));
NEW_PROP_TAG(LinearSolverConfiguration);
NEW_PROP_TAG(GlobalEqVector);
NEW_PROP_TAG(SparseMatrixAdapter);
NEW_PROP_TAG(Simulator);
END_PROPERTIES
namespace Opm
{
//=====================================================================
// Implementation for ISTL-matrix based operator
//=====================================================================
/// This class solves the fully implicit black-oil system by
/// solving the reduced system (after eliminating well variables)
/// as a block-structured matrix (one block for all cell variables) for a fixed
/// number of cell variables.
///
/// The solvers and preconditioners used are run-time configurable.
template <class TypeTag>
class ISTLSolverEbosFlexible
{
using SparseMatrixAdapter = typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter);
using VectorType = typename GET_PROP_TYPE(TypeTag, GlobalEqVector);
using Simulator = typename GET_PROP_TYPE(TypeTag, Simulator);
using MatrixType = typename SparseMatrixAdapter::IstlMatrix;
using POrComm = Dune::Amg::SequentialInformation;
using MatrixAdapterType = Dune::MatrixAdapter<MatrixType, VectorType, VectorType>;
using SolverType = Dune::FlexibleSolver<MatrixType, VectorType>;
public:
static void registerParameters()
{
FlowLinearSolverParameters::registerParameters<TypeTag>();
}
explicit ISTLSolverEbosFlexible(const Simulator& simulator)
: simulator_(simulator)
{
parameters_.template init<TypeTag>();
}
void eraseMatrix()
{
}
void prepare(const SparseMatrixAdapter& mat, VectorType& b)
{
boost::property_tree::ptree prm = setupPropertyTree(parameters_);
solver_.reset(new SolverType(prm, mat.istlMatrix()));
rhs_ = b;
}
bool solve(VectorType& x)
{
solver_->apply(x, rhs_, res_);
return res_.converged;
}
bool isParallel()
{
return false;
}
int iterations() const
{
return res_.iterations;
}
void setResidual(VectorType& /* b */)
{
// rhs_ = &b; // Must be handled in prepare() instead.
}
void setMatrix(const SparseMatrixAdapter& /* M */)
{
// matrix_ = &M.istlMatrix(); // Must be handled in prepare() instead.
}
protected:
const Simulator& simulator_;
std::unique_ptr<SolverType> solver_;
FlowLinearSolverParameters parameters_;
VectorType rhs_;
Dune::InverseOperatorResult res_;
}; // end ISTLSolverEbosFlexible
} // namespace Opm
#endif // OPM_ISTLSOLVEREBOSFLEXIBLE_HEADER_INCLUDED

View File

@ -0,0 +1,100 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2019 Dr. Blatt - HPC-Simulation-Software & Services.
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 3 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/>.
*/
#ifndef OPM_MATRIXMARKETUTILS_HEADER_INCLUDED
#define OPM_MATRIXMARKETUTILS_HEADER_INCLUDED
#include <dune/istl/matrixmarket.hh>
#include <cstddef>
namespace Dune
{
namespace MatrixMarketImpl
{
template <typename T, typename A, int brows, int bcols, typename D>
void makeSparseEntries(Dune::BCRSMatrix<Dune::FieldMatrix<T, brows, bcols>, A>& matrix,
std::vector<int>& i,
std::vector<int>& j,
std::vector<double>& val,
const D&)
{
// addapted from readSparseEntries
typedef Dune::BCRSMatrix<Dune::FieldMatrix<T, brows, bcols>, A> Matrix;
std::vector<std::set<IndexData<D>>> rows(matrix.N() * brows);
for (std::size_t kk = 0; kk < i.size(); ++kk) {
std::size_t row;
IndexData<D> data;
row = i[kk];
assert(row / bcols < matrix.N());
data.number = val[kk];
data.index = j[kk];
assert(data.index / bcols < matrix.M());
rows[row].insert(data);
}
// Setup the matrix sparsity pattern
int nnz = 0;
for (typename Matrix::CreateIterator iter = matrix.createbegin(); iter != matrix.createend(); ++iter) {
for (std::size_t brow = iter.index() * brows, browend = iter.index() * brows + brows; brow < browend;
++brow) {
typedef typename std::set<IndexData<D>>::const_iterator Siter;
for (Siter siter = rows[brow].begin(), send = rows[brow].end(); siter != send; ++siter, ++nnz)
iter.insert(siter->index / bcols);
}
}
// Set the matrix values
matrix = 0;
MatrixValuesSetter<D, brows, bcols> Setter;
Setter(rows, matrix);
}
} // end namespace MatrixMarketImpl
template <typename T, typename A, int brows, int bcols>
void
makeMatrixMarket(Dune::BCRSMatrix<Dune::FieldMatrix<T, brows, bcols>, A>& matrix,
std::vector<int> i,
std::vector<int> j,
std::vector<T> val,
size_t rows,
size_t cols)
{
// addapted from readMatrixMarket
using namespace MatrixMarketImpl;
// std::size_t rows, cols, entries;
// std::size_t nnz, blockrows, blockcols;
// std::tie(blockrows, blockcols, nnz) = calculateNNZ<brows, bcols>(rows, cols, entries, header);
std::size_t blockrows = rows / brows;
std::size_t blockcols = cols / bcols;
matrix.setSize(blockrows, blockcols);
matrix.setBuildMode(Dune::BCRSMatrix<Dune::FieldMatrix<T, brows, bcols>, A>::row_wise);
makeSparseEntries(matrix, i, j, val, NumericWrapper<T>());
}
} // end namespace Dune
#endif // OPM_MATRIXMARKETUTILS_HEADER_INCLUDED

View File

@ -0,0 +1,123 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_OWNINGTWOLEVELPRECONDITIONER_HEADER_INCLUDED
#define OPM_OWNINGTWOLEVELPRECONDITIONER_HEADER_INCLUDED
#include <opm/simulators/linalg/PressureSolverPolicy.hpp>
#include <opm/simulators/linalg/PressureTransferPolicy.hpp>
#include <opm/simulators/linalg/getQuasiImpesWeights.hpp>
#include <dune/common/fmatrix.hh>
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/paamg/amg.hh>
#include <boost/property_tree/ptree.hpp>
#include <fstream>
namespace Dune
{
// Circular dependency between makePreconditioner() [which can make an OwningTwoLevelPreconditioner]
// and OwningTwoLevelPreconditioner [which uses makePreconditioner() to choose the fine-level smoother]
// must be broken, accomplished by forward-declaration here.
template <class MatrixType, class VectorType>
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>>
makePreconditioner(const Dune::MatrixAdapter<MatrixType, VectorType, VectorType>& linearoperator,
const boost::property_tree::ptree& prm);
// Must forward-declare FlexibleSolver as we want to use it as solver for the pressure system.
template <class MatrixTypeT, class VectorTypeT>
class FlexibleSolver;
template <class MatrixTypeT, class VectorTypeT, bool transpose = false>
class OwningTwoLevelPreconditioner : public Dune::Preconditioner<VectorTypeT, VectorTypeT>
{
public:
using pt = boost::property_tree::ptree;
using MatrixType = MatrixTypeT;
using VectorType = VectorTypeT;
using OperatorType = Dune::MatrixAdapter<MatrixType, VectorType, VectorType>;
OwningTwoLevelPreconditioner(OperatorType& linearoperator, pt& prm)
: finesmoother_(makePreconditioner<MatrixType, VectorType>(linearoperator, prm.get_child("finesmoother")))
, comm_()
, weights_(Opm::Amg::getQuasiImpesWeights<MatrixType, VectorType>(
linearoperator.getmat(), prm.get<int>("pressure_var_index"), transpose))
, levelTransferPolicy_(comm_, weights_, prm.get<int>("pressure_var_index"))
, coarseSolverPolicy_(prm.get_child("coarsesolver"))
, twolevel_method_(linearoperator,
finesmoother_,
levelTransferPolicy_,
coarseSolverPolicy_,
transpose ? 1 : 0,
transpose ? 0 : 1)
{
if (prm.get<int>("verbosity") > 10) {
std::ofstream outfile(prm.get<std::string>("weights_filename"));
if (!outfile) {
throw std::runtime_error("Could not write weights");
}
Dune::writeMatrixMarket(weights_, outfile);
}
}
virtual void pre(VectorType& x, VectorType& b) override
{
twolevel_method_.pre(x, b);
}
virtual void apply(VectorType& v, const VectorType& d) override
{
twolevel_method_.apply(v, d);
}
virtual void post(VectorType& x) override
{
twolevel_method_.post(x);
}
virtual Dune::SolverCategory::Category category() const override
{
return Dune::SolverCategory::sequential;
}
private:
using PressureMatrixType = Dune::BCRSMatrix<Dune::FieldMatrix<double, 1, 1>>;
using PressureVectorType = Dune::BlockVector<Dune::FieldVector<double, 1>>;
using CoarseOperatorType = Dune::MatrixAdapter<PressureMatrixType, PressureVectorType, PressureVectorType>;
using Communication = Dune::Amg::SequentialInformation;
using LevelTransferPolicy = Opm::PressureTransferPolicy<OperatorType, CoarseOperatorType, Communication, transpose>;
using CoarseSolverPolicy
= Dune::Amg::PressureSolverPolicy<CoarseOperatorType, FlexibleSolver<PressureMatrixType, PressureVectorType>>;
using TwoLevelMethod
= Dune::Amg::TwoLevelMethod<OperatorType, CoarseSolverPolicy, Dune::Preconditioner<VectorType, VectorType>>;
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>> finesmoother_;
Communication comm_;
VectorType weights_;
LevelTransferPolicy levelTransferPolicy_;
CoarseSolverPolicy coarseSolverPolicy_;
TwoLevelMethod twolevel_method_;
};
} // namespace Dune
#endif // OPM_OWNINGTWOLEVELPRECONDITIONER_HEADER_INCLUDED

View File

@ -0,0 +1,114 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_PRESSURE_SOLVER_POLICY_HEADER_INCLUDED
#define OPM_PRESSURE_SOLVER_POLICY_HEADER_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <dune/istl/solver.hh>
namespace Dune
{
namespace Amg
{
namespace pt = boost::property_tree;
template <class OperatorType, class Solver>
class PressureSolverPolicy
{
public:
/** @brief The type of the linear operator used. */
using Operator = OperatorType;
/**
* @brief Constructs the coarse solver policy.
* @param prm Parameter tree specifying the solver details.
*/
explicit PressureSolverPolicy(const pt::ptree prm)
: prm_(prm)
{
}
private:
using X = typename Operator::range_type;
/**
* @brief A wrapper that makes an inverse operator out of AMG.
*
* The operator will use one step of AMG to approximately solve
* the coarse level system.
*/
struct PressureInverseOperator : public Dune::InverseOperator<X, X> {
PressureInverseOperator(Operator& op, const boost::property_tree::ptree& prm)
: linsolver_()
{
linsolver_.reset(new Solver(prm, op.getmat()));
}
Dune::SolverCategory::Category category() const override
{
return Dune::SolverCategory::sequential;
}
void apply(X& x, X& b, double reduction, Dune::InverseOperatorResult& res) override
{
linsolver_->apply(x, b, reduction, res);
}
void apply(X& x, X& b, Dune::InverseOperatorResult& res) override
{
linsolver_->apply(x, b, res);
}
private:
std::shared_ptr<Solver> linsolver_;
};
public:
/** @brief The type of solver constructed for the coarse level. */
using CoarseLevelSolver = PressureInverseOperator;
/**
* @brief Constructs a coarse level solver.
*
* @param transferPolicy The policy describing the transfer between levels.
* @return A pointer to the constructed coarse level solver.
*/
template <class LTP>
void setCoarseOperator(LTP& transferPolicy)
{
coarseOperator_ = transferPolicy.getCoarseLevelOperator();
}
template <class LTP>
CoarseLevelSolver* createCoarseLevelSolver(LTP& transferPolicy)
{
coarseOperator_ = transferPolicy.getCoarseLevelOperator();
PressureInverseOperator* inv = new PressureInverseOperator(*coarseOperator_, prm_);
return inv;
}
private:
/** @brief The coarse level operator. */
std::shared_ptr<Operator> coarseOperator_;
pt::ptree prm_;
};
} // namespace Amg
} // namespace Dune
#endif // OPM_PRESSURE_SOLVER_POLICY_HEADER_INCLUDED

View File

@ -0,0 +1,158 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2019 Dr. Blatt - HPC-Simulation-Software & Services.
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 3 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/>.
*/
#ifndef OPM_PRESSURE_TRANSFER_POLICY_HEADER_INCLUDED
#define OPM_PRESSURE_TRANSFER_POLICY_HEADER_INCLUDED
#include <dune/istl/paamg/twolevelmethod.hh>
namespace Opm
{
template <class FineOperator, class CoarseOperator, class Communication, bool transpose = false>
class PressureTransferPolicy : public Dune::Amg::LevelTransferPolicy<FineOperator, CoarseOperator>
{
public:
typedef Dune::Amg::LevelTransferPolicy<FineOperator, CoarseOperator> FatherType;
typedef Communication ParallelInformation;
typedef typename FineOperator::domain_type FineVectorType;
public:
PressureTransferPolicy(const Communication& comm, const FineVectorType& weights, int pressure_var_index)
: communication_(&const_cast<Communication&>(comm))
, weights_(weights)
, pressure_var_index_(pressure_var_index)
{
}
void createCoarseLevelSystem(const FineOperator& fineOperator)
{
using CoarseMatrix = typename CoarseOperator::matrix_type;
const auto& fineLevelMatrix = fineOperator.getmat();
coarseLevelMatrix_.reset(new CoarseMatrix(fineLevelMatrix.N(), fineLevelMatrix.M(), CoarseMatrix::row_wise));
auto createIter = coarseLevelMatrix_->createbegin();
for (const auto& row : fineLevelMatrix) {
for (auto col = row.begin(), cend = row.end(); col != cend; ++col) {
createIter.insert(col.index());
}
++createIter;
}
calculateCoarseEntries(fineOperator);
coarseLevelCommunication_.reset(communication_, [](Communication*) {});
this->lhs_.resize(this->coarseLevelMatrix_->M());
this->rhs_.resize(this->coarseLevelMatrix_->N());
using OperatorArgs = typename Dune::Amg::ConstructionTraits<CoarseOperator>::Arguments;
OperatorArgs oargs(*coarseLevelMatrix_, *coarseLevelCommunication_);
this->operator_.reset(Dune::Amg::ConstructionTraits<CoarseOperator>::construct(oargs));
}
void calculateCoarseEntries(const FineOperator& fineOperator)
{
const auto& fineMatrix = fineOperator.getmat();
*coarseLevelMatrix_ = 0;
auto rowCoarse = coarseLevelMatrix_->begin();
for (auto row = fineMatrix.begin(), rowEnd = fineMatrix.end(); row != rowEnd; ++row, ++rowCoarse) {
assert(row.index() == rowCoarse.index());
auto entryCoarse = rowCoarse->begin();
for (auto entry = row->begin(), entryEnd = row->end(); entry != entryEnd; ++entry, ++entryCoarse) {
assert(entry.index() == entryCoarse.index());
double matrix_el = 0;
if (transpose) {
auto bw = weights_[entry.index()];
for (size_t i = 0; i < bw.size(); ++i) {
matrix_el += (*entry)[pressure_var_index_][i] * bw[i];
}
} else {
auto bw = weights_[row.index()];
for (size_t i = 0; i < bw.size(); ++i) {
matrix_el += (*entry)[i][pressure_var_index_] * bw[i];
}
}
(*entryCoarse) = matrix_el;
}
}
assert(rowCoarse == coarseLevelMatrix_->end());
}
void moveToCoarseLevel(const typename FatherType::FineRangeType& fine)
{
// Set coarse vector to zero
this->rhs_ = 0;
auto end = fine.end(), begin = fine.begin();
for (auto block = begin; block != end; ++block) {
auto bw = weights_[block.index()];
double rhs_el = 0.0;
if (transpose) {
rhs_el = (*block)[pressure_var_index_];
} else {
for (size_t i = 0; i < block->size(); ++i) {
rhs_el += (*block)[i] * bw[i];
}
}
this->rhs_[block - begin] = rhs_el;
}
this->lhs_ = 0;
}
void moveToFineLevel(typename FatherType::FineDomainType& fine)
{
auto end = fine.end(), begin = fine.begin();
for (auto block = begin; block != end; ++block) {
if (transpose) {
auto bw = weights_[block.index()];
for (size_t i = 0; i < block->size(); ++i) {
(*block)[i] = this->lhs_[block - begin] * bw[i];
}
} else {
(*block)[pressure_var_index_] = this->lhs_[block - begin];
}
}
}
PressureTransferPolicy* clone() const
{
return new PressureTransferPolicy(*this);
}
const Communication& getCoarseLevelCommunication() const
{
return *coarseLevelCommunication_;
}
private:
Communication* communication_;
const FineVectorType& weights_;
const int pressure_var_index_;
std::shared_ptr<Communication> coarseLevelCommunication_;
std::shared_ptr<typename CoarseOperator::matrix_type> coarseLevelMatrix_;
};
} // namespace Opm
#endif // OPM_PRESSURE_TRANSFER_POLICY_HEADER_INCLUDED

View File

@ -0,0 +1,90 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_GET_QUASI_IMPES_WEIGHTS_HEADER_INCLUDED
#define OPM_GET_QUASI_IMPES_WEIGHTS_HEADER_INCLUDED
#include <algorithm>
#include <cmath>
namespace Opm
{
namespace Details
{
template <class DenseMatrix>
DenseMatrix transposeDenseMatrix(const DenseMatrix& M)
{
DenseMatrix tmp;
for (int i = 0; i < M.rows; ++i)
for (int j = 0; j < M.cols; ++j)
tmp[j][i] = M[i][j];
return tmp;
}
} // namespace Details
namespace Amg
{
template <class Matrix, class Vector>
void getQuasiImpesWeights(const Matrix& matrix, const int pressureVarIndex, Vector& weights, bool transpose = false)
{
using VectorBlockType = typename Vector::block_type;
using MatrixBlockType = typename Matrix::block_type;
const Matrix& A = matrix;
VectorBlockType rhs(0.0);
rhs[pressureVarIndex] = 1.0;
const auto endi = A.end();
for (auto i = A.begin(); i != endi; ++i) {
const auto endj = (*i).end();
MatrixBlockType diag_block(0.0);
for (auto j = (*i).begin(); j != endj; ++j) {
if (i.index() == j.index()) {
diag_block = (*j);
break;
}
}
VectorBlockType bweights;
if (transpose) {
diag_block.solve(bweights, rhs);
} else {
auto diag_block_transpose = Opm::Details::transposeDenseMatrix(diag_block);
diag_block_transpose.solve(bweights, rhs);
}
double abs_max = *std::max_element(
bweights.begin(), bweights.end(), [](double a, double b) { return std::fabs(a) < std::fabs(b); });
bweights /= std::fabs(abs_max);
weights[i.index()] = bweights;
}
// return weights;
}
template <class Matrix, class Vector>
Vector getQuasiImpesWeights(const Matrix& matrix, const int pressureVarIndex, bool transpose = false)
{
Vector weights(matrix.N());
getQuasiImpesWeights(matrix, pressureVarIndex, weights, transpose);
return weights;
}
} // namespace Amg
} // namespace Opm
#endif // OPM_GET_QUASI_IMPES_WEIGHTS_HEADER_INCLUDED

View File

@ -0,0 +1,193 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_MAKEPRECONDITIONER_HEADER_INCLUDED
#define OPM_MAKEPRECONDITIONER_HEADER_INCLUDED
#include <opm/simulators/linalg/OwningTwoLevelPreconditioner.hpp>
#include <opm/simulators/linalg/ParallelOverlappingILU0.hpp>
#include <dune/istl/paamg/amg.hh>
#include <dune/istl/paamg/fastamg.hh>
#include <dune/istl/preconditioners.hh>
#include <boost/property_tree/ptree.hpp>
namespace Dune
{
template <class MatrixType, class VectorType>
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>>
makeSeqPreconditioner(const Dune::MatrixAdapter<MatrixType, VectorType, VectorType>& linearoperator,
const boost::property_tree::ptree& prm)
{
auto& matrix = linearoperator.getmat();
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>> preconditioner;
double w = prm.get<double>("w");
int n = prm.get<int>("n");
std::string precond(prm.get<std::string>("preconditioner"));
if (precond == "ILU0") {
preconditioner.reset(new Dune::SeqILU0<MatrixType, VectorType, VectorType>(matrix, w));
} else if (precond == "ParOverILU0") {
preconditioner.reset(new Opm::ParallelOverlappingILU0<MatrixType, VectorType, VectorType>(matrix, n, w, Opm::MILU_VARIANT::ILU));
} else if (precond == "Jac") {
preconditioner.reset(new Dune::SeqJac<MatrixType, VectorType, VectorType>(matrix, n, w));
} else if (precond == "GS") {
preconditioner.reset(new Dune::SeqGS<MatrixType, VectorType, VectorType>(matrix, n, w));
} else if (precond == "SOR") {
preconditioner.reset(new Dune::SeqSOR<MatrixType, VectorType, VectorType>(matrix, n, w));
} else if (precond == "SSOR") {
preconditioner.reset(new Dune::SeqSSOR<MatrixType, VectorType, VectorType>(matrix, n, w));
} else if (precond == "ILUn") {
preconditioner.reset(new Dune::SeqILUn<MatrixType, VectorType, VectorType>(matrix, n, w));
} else {
std::string msg("No such seq preconditioner : ");
msg += precond;
throw std::runtime_error(msg);
}
return preconditioner;
}
template <class Smoother, class MatrixType, class VectorType>
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>>
makeAmgPreconditioner(Dune::MatrixAdapter<MatrixType, VectorType, VectorType>& linearoperator,
const boost::property_tree::ptree& global_prm)
{
boost::property_tree::ptree prm = global_prm.get_child("amg");
typedef Dune::MatrixAdapter<MatrixType, VectorType, VectorType> OperatorType;
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>> preconditioner;
typedef Dune::Amg::AggregationCriterion<Dune::Amg::SymmetricMatrixDependency<MatrixType, Dune::Amg::FirstDiagonal>>
CriterionBase;
typedef Dune::Amg::CoarsenCriterion<CriterionBase> Criterion;
int coarsenTarget = prm.get<int>("coarsenTarget");
int ml = prm.get<int>("maxlevel");
Criterion criterion(15, coarsenTarget);
criterion.setDefaultValuesIsotropic(2);
criterion.setAlpha(prm.get<double>("alpha"));
criterion.setBeta(prm.get<double>("beta"));
criterion.setMaxLevel(ml);
criterion.setSkipIsolated(false);
criterion.setDebugLevel(prm.get<int>("verbosity"));
if (global_prm.get<std::string>("preconditioner") == "famg") {
Dune::Amg::Parameters parms;
parms.setNoPreSmoothSteps(1);
parms.setNoPostSmoothSteps(1);
preconditioner.reset(new Dune::Amg::FastAMG<OperatorType, VectorType>(linearoperator, criterion, parms));
} else {
typedef typename Dune::Amg::SmootherTraits<Smoother>::Arguments SmootherArgs;
SmootherArgs smootherArgs;
smootherArgs.iterations = prm.get<int>("n");
// smootherArgs.overlap=SmootherArgs::vertex;
// smootherArgs.overlap=SmootherArgs::none;
// smootherArgs.overlap=SmootherArgs::aggregate;
smootherArgs.relaxationFactor = prm.get<double>("w");
preconditioner.reset(
new Dune::Amg::AMG<OperatorType, VectorType, Smoother>(linearoperator, criterion, smootherArgs));
}
return preconditioner;
}
template <class MatrixType, class VectorType>
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>>
makeAmgPreconditioners(Dune::MatrixAdapter<MatrixType, VectorType, VectorType>& linearoperator,
const boost::property_tree::ptree& prm)
{
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>> preconditioner;
if (prm.get<std::string>("preconditioner") == "famg") {
// smoother type should not be used
preconditioner
= makeAmgPreconditioner<Dune::SeqILU0<MatrixType, VectorType, VectorType>, MatrixType, VectorType>(
linearoperator, prm);
return preconditioner;
}
std::string precond = prm.get<std::string>("amg.smoother");
if (precond == "ILU0") {
preconditioner
= makeAmgPreconditioner<Dune::SeqILU0<MatrixType, VectorType, VectorType>, MatrixType, VectorType>(
linearoperator, prm);
} else if (precond == "Jac") {
preconditioner
= makeAmgPreconditioner<Dune::SeqJac<MatrixType, VectorType, VectorType>, MatrixType, VectorType>(
linearoperator, prm);
// }else if(precond == "GS"){
// preconditioner = makeAmgPreconditioner<
// Dune::SeqGS<MatrixType, VectorType, VectorType>,
// MatrixType, VectorType>(linearoperator,prm);
} else if (precond == "SOR") {
preconditioner
= makeAmgPreconditioner<Dune::SeqSOR<MatrixType, VectorType, VectorType>, MatrixType, VectorType>(
linearoperator, prm);
} else if (precond == "SSOR") {
preconditioner
= makeAmgPreconditioner<Dune::SeqSSOR<MatrixType, VectorType, VectorType>, MatrixType, VectorType>(
linearoperator, prm);
} else if (precond == "ILUn") {
preconditioner
= makeAmgPreconditioner<Dune::SeqILUn<MatrixType, VectorType, VectorType>, MatrixType, VectorType>(
linearoperator, prm);
} else {
std::string msg("No such seq preconditioner : ");
msg += precond;
throw std::runtime_error(msg);
}
return preconditioner;
}
template <class MatrixType, class VectorType>
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>>
makeTwoLevelPreconditioner(Dune::MatrixAdapter<MatrixType, VectorType, VectorType>& linearoperator,
const boost::property_tree::ptree& global_prm)
{
boost::property_tree::ptree prm = global_prm.get_child("cpr");
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>> preconditioner;
if (global_prm.get<std::string>("preconditioner") == "cpr") {
preconditioner.reset(new OwningTwoLevelPreconditioner<MatrixType, VectorType, false>(linearoperator, prm));
} else if (global_prm.get<std::string>("preconditioner") == "cprt") {
preconditioner.reset(new OwningTwoLevelPreconditioner<MatrixType, VectorType, true>(linearoperator, prm));
} else {
std::string msg("Wrong cpr Should not happen");
throw std::runtime_error(msg);
}
return preconditioner;
}
template <class MatrixType, class VectorType>
std::shared_ptr<Dune::Preconditioner<VectorType, VectorType>>
makePreconditioner(Dune::MatrixAdapter<MatrixType, VectorType, VectorType>& linearoperator,
const boost::property_tree::ptree& prm)
{
if ((prm.get<std::string>("preconditioner") == "famg") or (prm.get<std::string>("preconditioner") == "amg")) {
return makeAmgPreconditioners<MatrixType, VectorType>(linearoperator, prm);
} else if ((prm.get<std::string>("preconditioner") == "cpr")
or (prm.get<std::string>("preconditioner") == "cprt")) {
return makeTwoLevelPreconditioner<MatrixType, VectorType>(linearoperator, prm);
} else {
return makeSeqPreconditioner<MatrixType, VectorType>(linearoperator, prm);
}
}
} // namespace Dune
#endif // OPM_MAKEPRECONDITIONER_HEADER_INCLUDED

View File

@ -0,0 +1,115 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#include <opm/simulators/linalg/setupPropertyTree.hpp>
#include <boost/property_tree/json_parser.hpp>
namespace Opm
{
boost::property_tree::ptree setupPropertyTree(const FlowLinearSolverParameters& p)
{
boost::property_tree::ptree prm;
if (p.linear_solver_configuration_json_file_ != "none") {
boost::property_tree::read_json(p.linear_solver_configuration_json_file_, prm);
} else {
prm.put("tol", p.linear_solver_reduction_);
prm.put("maxiter", p.linear_solver_maxiter_);
prm.put("verbosity", p.linear_solver_verbosity_);
prm.put("preconditioner", "ILU0");
prm.put("solver", "bicgstab");
prm.put("w", 1.0);
prm.put("n", 1);
}
/*
prm.put("tol", 0.5);
prm.put("maxiter", 20);
prm.put("preconditioner", "cpr");
prm.put("w", 1);
prm.put("n", 1);
prm.put("cpr.finesmoother.preconditioner", "ILU0");
prm.put("cpr.finesmoother.w", 1);
prm.put("cpr.finesmoother.n", 1);
prm.put("cpr.coarsesolver.tol", 0.5);
prm.put("cpr.coarsesolver.maxiter", 20);
prm.put("cpr.coarsesolver.preconditioner", "amg");
prm.put("cpr.coarsesolver.amg.maxlevel", 5);
prm.put("cpr.coarsesolver.amg.coarsenTarget", 1000);
prm.put("cpr.coarsesolver.amg.smoother", "ILU0");
prm.put("cpr.coarsesolver.amg.alpha", 0.2);
prm.put("cpr.coarsesolver.amg.beta", 0.0001);
prm.put("cpr.coarsesolver.amg.verbosity", 0);
prm.put("cpr.coarsesolver.amg.n", 1);
prm.put("cpr.coarsesolver.amg.w", 1);
prm.put("cpr.coarsesolver.verbosity", 0);
prm.put("cpr.coarsesolver.solver", "bicgstab");
prm.put("cpr.verbosity", 11);
prm.put("cpr.weights_filename" , "weight_cpr.txt");
prm.put("cpr.pressure_var_index" , 1);
prm.put("verbosity", 10);
prm.put("solver", "bicgstab");
prm.put("restart", 20);
*/
return prm;
}
} // namespace Opm
/*
{
"tol": "0.5",
"maxiter": "20",
"preconditioner": "cpr",
"w": "1",
"n": "1",
"amg": "",
"cpr": {
"finesmoother": {
"preconditioner": "ILU0",
"w": "1",
"n": "1"
},
"coarsesolver": {
"tol": "0.5",
"maxiter": "20",
"preconditioner": "amg",
"amg": {
"maxlevel": "5",
"coarsenTarget": "1000",
"smoother": "ILU0",
"alpha": "0.2",
"beta": "0.0001",
"verbosity": "0",
"n": "1",
"w": "1"
},
"verbosity": "0",
"solver": "bicgstab"
},
"verbosity": "11",
"weights_filename" : "weight_cpr.txt",
"pressure_var_index" : "1"
},
"verbosity": "10",
"solver": "bicgstab",
"restart": "20"
}
*/

View File

@ -0,0 +1,34 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#ifndef OPM_SETUPPROPERTYTREE_HEADER_INCLUDED
#define OPM_SETUPPROPERTYTREE_HEADER_INCLUDED
#include <opm/simulators/linalg/FlowLinearSolverParameters.hpp>
#include <boost/property_tree/ptree.hpp>
namespace Opm
{
boost::property_tree::ptree setupPropertyTree(const FlowLinearSolverParameters& p);
} // namespace Opm
#endif // OPM_SETUPPROPERTYTREE_HEADER_INCLUDED

66
tests/matr33.txt Normal file
View File

@ -0,0 +1,66 @@
%%MatrixMarket matrix coordinate real general
% ISTL_STRUCT blocked 3 3
9 9 63
1 1 1.63148e-07
1 2 0.126774
1 3 -6.09774e-05
2 1 4.64465e-10
2 2 -0.0987407
2 3 -5.86038e-05
3 1 5.66966e-08
3 2 -12.0531
3 3 0.0462478
1 4 -8.84841e-11
1 5 -5.64705e-05
1 6 0
2 4 -3.93176e-10
2 5 0
2 6 0
3 4 -4.79944e-08
3 5 0
3 6 0
4 1 -8.89921e-11
4 2 -0.00786145
4 3 0
5 1 -3.53139e-10
5 2 0.0283977
5 3 -3.79289e-05
6 1 -4.31072e-08
6 2 3.46646
6 3 -0.00944335
4 4 1.20862e-10
4 5 0.0829656
4 6 0
5 4 7.40377e-10
5 5 -0.0929483
5 6 -0.0967963
6 4 4.64141e-07
6 5 -9.10276
6 6 16.3772
4 7 -2.168e-11
4 8 -1.38362e-05
4 9 0
5 7 -7.8331e-10
5 8 0
5 9 0
6 7 -1.20687e-07
6 8 0
6 9 0
7 4 -2.17548e-11
7 5 -0.00183118
7 6 0
8 4 -8.00212e-10
8 5 0.0276779
8 6 0.0320899
9 4 -1.56667e-07
9 5 2.7106
9 6 -7.32919
7 7 4.43266e-09
7 8 0.0744616
7 9 0
8 7 1.59375e-07
8 8 -0.0899451
8 9 -0.0940009
9 7 2.86852e-05
9 8 -5.63337
9 9 13.3423

View File

@ -0,0 +1,38 @@
{
"tol": "0.5",
"maxiter": "20",
"preconditioner": "cpr",
"w": "1",
"n": "1",
"amg": "",
"cpr": {
"finesmoother": {
"preconditioner": "ILU0",
"w": "1",
"n": "1"
},
"coarsesolver": {
"tol": "0.5",
"maxiter": "20",
"preconditioner": "amg",
"amg": {
"maxlevel": "5",
"coarsenTarget": "1000",
"smoother": "ILU0",
"alpha": "0.2",
"beta": "0.0001",
"verbosity": "0",
"n": "1",
"w": "1"
},
"verbosity": "0",
"solver": "bicgstab"
},
"verbosity": "11",
"weights_filename" : "weight_cpr.txt",
"pressure_var_index" : "1"
},
"verbosity": "10",
"solver": "bicgstab",
"restart": "20"
}

12
tests/rhs3.txt Normal file
View File

@ -0,0 +1,12 @@
%%MatrixMarket matrix array real general
% ISTL_STRUCT blocked 3 1
9 1
-4.48332e-07
3.53746e-07
4.31812e-05
1.48051e-07
-5.76325e-07
-0.000243496
-3.81652e-08
1.21761e-06
-9.97615e-05

View File

@ -0,0 +1,108 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
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 3 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/>.
*/
#include <config.h>
#define BOOST_TEST_MODULE OPM_test_FlexibleSolver
#include <boost/test/unit_test.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fstream>
#include <iostream>
#include <opm/simulators/linalg/FlexibleSolver.hpp>
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
testSolver(const boost::property_tree::ptree& prm, const std::string& matrix_filename, const std::string& rhs_filename)
{
using Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, bz, bz>>;
using Vector = Dune::BlockVector<Dune::FieldVector<double, bz>>;
Matrix matrix;
{
std::ifstream mfile(matrix_filename);
if (!mfile) {
throw std::runtime_error("Could not read matrix file");
}
readMatrixMarket(matrix, mfile);
}
Vector rhs;
{
std::ifstream rhsfile(rhs_filename);
if (!rhsfile) {
throw std::runtime_error("Could not read rhs file");
}
readMatrixMarket(rhs, rhsfile);
}
Dune::FlexibleSolver<Matrix, Vector> solver(prm, matrix);
Vector x(rhs.size());
Dune::InverseOperatorResult res;
solver.apply(x, rhs, res);
return x;
}
BOOST_AUTO_TEST_CASE(TestFlexibleSolver)
{
namespace pt = boost::property_tree;
pt::ptree prm;
// Read parameters.
{
std::ifstream file("options_flexiblesolver.json");
pt::read_json(file, prm);
// pt::write_json(std::cout, prm);
}
// Test with 1x1 block solvers.
{
const int bz = 1;
auto sol = testSolver<bz>(prm, "matr33.txt", "rhs3.txt");
Dune::BlockVector<Dune::FieldVector<double, bz>> expected {-1.62493,
-1.76435e-06,
1.86991e-10,
-458.542,
2.28308e-06,
-2.45341e-07,
-1.48005,
-5.02264e-07,
-1.049e-05};
BOOST_REQUIRE_EQUAL(sol.size(), expected.size());
for (size_t i = 0; i < sol.size(); ++i) {
for (int row = 0; row < bz; ++row) {
BOOST_CHECK_CLOSE(sol[i][row], expected[i][row], 1e-3);
}
}
}
// Test with 3x3 block solvers.
{
const int bz = 3;
auto sol = testSolver<bz>(prm, "matr33.txt", "rhs3.txt");
Dune::BlockVector<Dune::FieldVector<double, bz>> expected {{-1.62493, -1.76435e-06, 1.86991e-10},
{-458.542, 2.28308e-06, -2.45341e-07},
{-1.48005, -5.02264e-07, -1.049e-05}};
BOOST_REQUIRE_EQUAL(sol.size(), expected.size());
for (size_t i = 0; i < sol.size(); ++i) {
for (int row = 0; row < bz; ++row) {
BOOST_CHECK_CLOSE(sol[i][row], expected[i][row], 1e-3);
}
}
}
}