mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Version of cpr amg which can reuse setup and also change smoothers of fine and coarse system by changing tags
This commit is contained in:
parent
2932531572
commit
f05a9fdb25
@ -157,6 +157,16 @@ opm_add_test(flow
|
||||
flow/flow_ebos_oilwater_polymer.cpp
|
||||
flow/flow_ebos_oilwater_polymer_injectivity.cpp)
|
||||
|
||||
opm_add_test(flow_blackoil_dunecpr
|
||||
ONLY_COMPILE
|
||||
DEFAULT_ENABLE_IF ${FLOW_DEFAULT_ENABLE_IF}
|
||||
SOURCES flow/flow_blackoil_dunecpr.cpp
|
||||
EXE_NAME flow_blackoil_dunecpr
|
||||
DEPENDS "opmsimulators"
|
||||
LIBRARIES "opmsimulators")
|
||||
|
||||
|
||||
|
||||
if (BUILD_FLOW)
|
||||
install(TARGETS flow DESTINATION bin)
|
||||
opm_add_bash_completion(flow)
|
||||
|
@ -118,6 +118,9 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/autodiff/AquiferCarterTracy.hpp
|
||||
opm/autodiff/AquiferFetkovich.hpp
|
||||
opm/autodiff/BlackoilAmg.hpp
|
||||
opm/autodiff/BlackoilAmgCpr.hpp
|
||||
opm/autodiff/amgcpr.hh
|
||||
opm/autodiff/twolevelmethodcpr.hh
|
||||
opm/autodiff/BlackoilDetails.hpp
|
||||
opm/autodiff/BlackoilModelParametersEbos.hpp
|
||||
opm/autodiff/BlackoilAquiferModel.hpp
|
||||
@ -129,6 +132,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/autodiff/FlowMainEbos.hpp
|
||||
opm/autodiff/GraphColoring.hpp
|
||||
opm/autodiff/ISTLSolverEbos.hpp
|
||||
opm/autodiff/ISTLSolverEbosCpr.hpp
|
||||
opm/autodiff/IterationReport.hpp
|
||||
opm/autodiff/MatrixBlock.hpp
|
||||
opm/autodiff/moduleVersion.hpp
|
||||
|
125
flow/flow_blackoil_dunecpr.cpp
Normal file
125
flow/flow_blackoil_dunecpr.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright 2013, 2014, 2015 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2015, 2017 IRIS AS
|
||||
|
||||
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"
|
||||
#include "flow/flow_tag.hpp"
|
||||
//#include <opm/linearsolvers/amgclsolverbackend.hh>
|
||||
#include <opm/autodiff/ISTLSolverEbosCpr.hpp>
|
||||
//#include <ewoms/linear/superlubackend.hh>
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
NEW_TYPE_TAG(EclFlowProblemSimple, INHERITS_FROM(EclFlowProblem));
|
||||
NEW_PROP_TAG(FluidState);
|
||||
NEW_PROP_TAG(CprSmootherFine);
|
||||
NEW_PROP_TAG(CprSmootherCoarse);
|
||||
//SET_TYPE_PROP(EclBaseProblem, Problem, Ewoms::EclProblem<TypeTag>);
|
||||
SET_PROP(EclFlowProblemSimple, FluidState)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
|
||||
enum { enableTemperature = GET_PROP_VALUE(TypeTag, EnableTemperature) };
|
||||
enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) };
|
||||
enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) };
|
||||
enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) };
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
static const bool compositionSwitchEnabled = Indices::gasEnabled;
|
||||
|
||||
public:
|
||||
//typedef Opm::BlackOilFluidSystemSimple<Scalar> type;
|
||||
typedef Opm::BlackOilFluidState<Evaluation, FluidSystem, enableTemperature, enableEnergy, compositionSwitchEnabled, Indices::numPhases > type;
|
||||
};
|
||||
SET_PROP(EclFlowProblemSimple, CprSmootherFine)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) Vector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter) SparseMatrixAdapter;
|
||||
typedef typename SparseMatrixAdapter::IstlMatrix Matrix;
|
||||
typedef Dune::Amg::SequentialInformation POrComm;
|
||||
|
||||
public:
|
||||
typedef Opm::ParallelOverlappingILU0<Matrix,Vector,Vector, POrComm> type;
|
||||
//typedef Dune::SeqILU0<Matrix,Vector,Vector, POrComm> type;
|
||||
};
|
||||
|
||||
SET_PROP(EclFlowProblemSimple, CprSmootherCoarse)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) Vector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter) SparseMatrixAdapter;
|
||||
typedef typename SparseMatrixAdapter::IstlMatrix Matrix;
|
||||
typedef Dune::Amg::SequentialInformation POrComm;
|
||||
|
||||
public:
|
||||
typedef Opm::ParallelOverlappingILU0<Matrix,Vector,Vector, POrComm> type;
|
||||
//typedef Dune::SeqILU0<Matrix,Vector,Vector, POrComm> type;
|
||||
};
|
||||
|
||||
SET_BOOL_PROP(EclFlowProblemSimple,MatrixAddWellContributions,true);
|
||||
SET_INT_PROP(EclFlowProblemSimple,LinearSolverVerbosity,1);
|
||||
SET_SCALAR_PROP(EclFlowProblemSimple, LinearSolverReduction, 1e-4);
|
||||
SET_INT_PROP(EclFlowProblemSimple, LinearSolverMaxIter, 20);
|
||||
SET_BOOL_PROP(EclFlowProblemSimple, UseAmg, true);//probably not used
|
||||
SET_BOOL_PROP(EclFlowProblemSimple, UseCpr, true);
|
||||
SET_INT_PROP(EclFlowProblemSimple, CprMaxEllIter, 1);
|
||||
SET_INT_PROP(EclFlowProblemSimple, CprEllSolvetype, 3);
|
||||
SET_INT_PROP(EclFlowProblemSimple, CprReuseSetup, 3);
|
||||
SET_INT_PROP(EclFlowProblemSimple, CprSolverVerbose, 3);
|
||||
SET_STRING_PROP(EclFlowProblemSimple, SystemStrategy, "quasiimpes");
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Ewoms {
|
||||
namespace Properties {
|
||||
|
||||
SET_PROP(EclFlowProblemSimple, FluidSystem)
|
||||
{
|
||||
private:
|
||||
//typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
|
||||
public:
|
||||
typedef Opm::BlackOilFluidSystem<Scalar> type;
|
||||
};
|
||||
//NEW_TYPE_TAG(EclFlowProblem, INHERITS_FROM(BlackOilModel, EclBaseProblem));
|
||||
SET_TYPE_PROP(EclFlowProblemSimple, IntensiveQuantities, Ewoms::BlackOilIntensiveQuantities<TypeTag>);
|
||||
//SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbos<TypeTag>);
|
||||
//SET_TAG_PROP(EclFlowProblemSimple, LinearSolverSplice, ParallelBiCGStabLinearSolver);
|
||||
//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_BOOL_PROP(EclFlowProblemSimple, EnableStorageCache, true);
|
||||
SET_BOOL_PROP(EclFlowProblemSimple, EnableIntensiveQuantityCache, true);
|
||||
|
||||
//SET_INT_PROP(EclFlowProblemSimple, NumWellAdjoint, 1);
|
||||
//SET_BOOL_PROP(EclFlowProblem, EnableStorageCache, true);
|
||||
//SET_BOOL_PROP(EclFlowProblem, EnableIntensiveQuantityCache, true);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
typedef TTAG(EclFlowProblemSimple) TypeTag;
|
||||
return mainFlow<TypeTag>(argc, argv);
|
||||
}
|
212
flow/flow_tag.hpp
Normal file
212
flow/flow_tag.hpp
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
Copyright 2013, 2014, 2015 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2015, 2017 IRIS AS
|
||||
|
||||
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 FLOW_TAG_HPP
|
||||
#define FLOW_TAG_HPP
|
||||
#include <opm/autodiff/SimulatorFullyImplicitBlackoilEbos.hpp>
|
||||
#include <opm/autodiff/FlowMainEbos.hpp>
|
||||
#include <ewoms/common/propertysystem.hh>
|
||||
#include <ewoms/common/parametersystem.hh>
|
||||
#include <opm/autodiff/MissingFeatures.hpp>
|
||||
#include <opm/common/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/material/common/ResetLocale.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/checkDeck.hpp>
|
||||
|
||||
//#include <opm/material/fluidsystems/BlackOilFluidSystemSimple.hpp>
|
||||
//#include <opm/material/fluidsystems/BlackOilFluidSystemSimple.hpp>
|
||||
#include <ewoms/models/blackoil/blackoilintensivequantities.hh>
|
||||
#include <opm/material/fluidstates/BlackOilFluidState.hpp>
|
||||
//#include <opm/material/fluidstates/BlackOilFluidStateSimple.hpp>
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
#include <dune/fem/misc/mpimanager.hh>
|
||||
#else
|
||||
#include <dune/common/parallel/mpihelper.hh>
|
||||
#endif
|
||||
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
// this is a dummy type tag that is used to setup the parameters before the actual
|
||||
// simulator.
|
||||
NEW_TYPE_TAG(FlowEarlyBird, INHERITS_FROM(EclFlowProblem));
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Opm {
|
||||
template <class TypeTag>
|
||||
void flowEbosSetDeck(Deck &deck, EclipseState& eclState)
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Vanguard) Vanguard;
|
||||
Vanguard::setExternalDeck(&deck, &eclState);
|
||||
}
|
||||
|
||||
// ----------------- Main program -----------------
|
||||
template <class TypeTag>
|
||||
int flowEbosMain(int argc, char** argv)
|
||||
{
|
||||
// we always want to use the default locale, and thus spare us the trouble
|
||||
// with incorrect locale settings.
|
||||
Opm::resetLocale();
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
Dune::Fem::MPIManager::initialize(argc, argv);
|
||||
#else
|
||||
Dune::MPIHelper::instance(argc, argv);
|
||||
#endif
|
||||
Opm::FlowMainEbos<TypeTag> mainfunc;
|
||||
return mainfunc.execute(argc, argv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
boost::filesystem::path simulationCaseName( const std::string& casename ) {
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
const auto exists = []( const fs::path& f ) -> bool {
|
||||
if( !fs::exists( f ) ) return false;
|
||||
|
||||
if( fs::is_regular_file( f ) ) return true;
|
||||
|
||||
return fs::is_symlink( f )
|
||||
&& fs::is_regular_file( fs::read_symlink( f ) );
|
||||
};
|
||||
|
||||
auto simcase = fs::path( casename );
|
||||
|
||||
if( exists( simcase ) ) {
|
||||
return simcase;
|
||||
}
|
||||
|
||||
for( const auto& ext : { std::string("data"), std::string("DATA") } ) {
|
||||
if( exists( simcase.replace_extension( ext ) ) ) {
|
||||
return simcase;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::invalid_argument( "Cannot find input case " + casename );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Main program -----------------
|
||||
template<class TypeTag>
|
||||
int mainFlow(int argc, char** argv)
|
||||
{
|
||||
// MPI setup.
|
||||
#if HAVE_DUNE_FEM
|
||||
Dune::Fem::MPIManager::initialize(argc, argv);
|
||||
int mpiRank = Dune::Fem::MPIManager::rank();
|
||||
#else
|
||||
// the design of the plain dune MPIHelper class is quite flawed: there is no way to
|
||||
// get the instance without having the argc and argv parameters available and it is
|
||||
// not possible to determine the MPI rank and size without an instance. (IOW: the
|
||||
// rank() and size() methods are supposed to be static.)
|
||||
const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);
|
||||
int mpiRank = mpiHelper.rank();
|
||||
#endif
|
||||
|
||||
// we always want to use the default locale, and thus spare us the trouble
|
||||
// with incorrect locale settings.
|
||||
Opm::resetLocale();
|
||||
|
||||
// this is a work-around for a catch 22: we do not know what code path to use without
|
||||
// parsing the deck, but we don't know the deck without having access to the
|
||||
// parameters and this requires to know the type tag to be used. To solve this, we
|
||||
// use a type tag just for parsing the parameters before we instantiate the actual
|
||||
// simulator object. (Which parses the parameters again, but since this is done in an
|
||||
// identical manner it does not matter.)
|
||||
typedef TTAG(FlowEarlyBird) PreTypeTag;
|
||||
typedef GET_PROP_TYPE(PreTypeTag, Problem) PreProblem;
|
||||
|
||||
PreProblem::setBriefDescription("Simple Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project.");
|
||||
|
||||
int status = Opm::FlowMainEbos<PreTypeTag>::setupParameters_(argc, argv);
|
||||
if (status != 0)
|
||||
// if setupParameters_ returns a value smaller than 0, there was no error, but
|
||||
// the program should abort. This is the case e.g. for the --help and the
|
||||
// --print-properties parameters.
|
||||
return (status >= 0)?status:0;
|
||||
|
||||
bool outputCout = false;
|
||||
if (mpiRank == 0)
|
||||
outputCout = EWOMS_GET_PARAM(PreTypeTag, bool, EnableTerminalOutput);
|
||||
|
||||
std::string deckFilename = EWOMS_GET_PARAM(PreTypeTag, std::string, EclDeckFileName);
|
||||
typedef typename GET_PROP_TYPE(PreTypeTag, Vanguard) PreVanguard;
|
||||
try {
|
||||
deckFilename = PreVanguard::canonicalDeckPath(deckFilename).string();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Ewoms::Parameters::printUsage<PreTypeTag>(PreProblem::helpPreamble(argc, const_cast<const char**>(argv)),
|
||||
e.what());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create Deck and EclipseState.
|
||||
try {
|
||||
Opm::Parser parser;
|
||||
typedef std::pair<std::string, Opm::InputError::Action> ParseModePair;
|
||||
typedef std::vector<ParseModePair> ParseModePairs;
|
||||
ParseModePairs tmp;
|
||||
tmp.push_back(ParseModePair(Opm::ParseContext::PARSE_RANDOM_SLASH, Opm::InputError::IGNORE));
|
||||
tmp.push_back(ParseModePair(Opm::ParseContext::PARSE_MISSING_DIMS_KEYWORD, Opm::InputError::WARN));
|
||||
tmp.push_back(ParseModePair(Opm::ParseContext::SUMMARY_UNKNOWN_WELL, Opm::InputError::WARN));
|
||||
tmp.push_back(ParseModePair(Opm::ParseContext::SUMMARY_UNKNOWN_GROUP, Opm::InputError::WARN));
|
||||
Opm::ParseContext parseContext(tmp);
|
||||
Opm::ErrorGuard errorGuard;
|
||||
|
||||
std::shared_ptr<Opm::Deck> deck = std::make_shared< Opm::Deck >( parser.parseFile(deckFilename , parseContext, errorGuard) );
|
||||
if ( outputCout ) {
|
||||
Opm::checkDeck(*deck, parser);
|
||||
Opm::MissingFeatures::checkKeywords(*deck);
|
||||
}
|
||||
//Opm::Runspec runspec( *deck );
|
||||
//const auto& phases = runspec.phases();
|
||||
|
||||
std::shared_ptr<Opm::EclipseState> eclipseState = std::make_shared< Opm::EclipseState > ( *deck, parseContext, errorGuard );
|
||||
Opm::flowEbosSetDeck<TypeTag>(*deck, *eclipseState);
|
||||
return Opm::flowEbosMain<TypeTag>(argc, argv);
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
if (outputCout) {
|
||||
std::cerr << "Failed to create valid EclipseState object." << std::endl;
|
||||
std::cerr << "Exception caught: " << e.what() << std::endl;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
597
opm/autodiff/BlackoilAmgCpr.hpp
Normal file
597
opm/autodiff/BlackoilAmgCpr.hpp
Normal file
@ -0,0 +1,597 @@
|
||||
/*
|
||||
Copyright 2017 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_AMGCPR_HEADER_INCLUDED
|
||||
#define OPM_AMGCPR_HEADER_INCLUDED
|
||||
|
||||
#include <opm/autodiff/twolevelmethodcpr.hh>
|
||||
#include <ewoms/linear/matrixblock.hh>
|
||||
#include <opm/autodiff/ParallelOverlappingILU0.hpp>
|
||||
#include <opm/autodiff/FlowLinearSolverParameters.hpp>
|
||||
#include <opm/autodiff/CPRPreconditioner.hpp>
|
||||
#include <opm/autodiff/amgcpr.hh>
|
||||
#include <dune/istl/paamg/twolevelmethod.hh>
|
||||
#include <dune/istl/paamg/aggregates.hh>
|
||||
#include <dune/istl/bvector.hh>
|
||||
#include <dune/istl/bcrsmatrix.hh>
|
||||
#include <dune/istl/preconditioners.hh>
|
||||
#include <dune/istl/schwarz.hh>
|
||||
#include <dune/istl/operators.hh>
|
||||
#include <dune/istl/scalarproducts.hh>
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/fmatrix.hh>
|
||||
namespace Dune
|
||||
{
|
||||
namespace Amg
|
||||
{
|
||||
template<class M, class Norm>
|
||||
class UnSymmetricCriterion;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Dune
|
||||
{
|
||||
|
||||
template <class Scalar, int n, int m>
|
||||
class MatrixBlock;
|
||||
|
||||
}
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
template<class Operator, class Communication,class Vector>
|
||||
std::unique_ptr<typename Operator::matrix_type> scaleMatrixDRSPtr(const Operator& op,
|
||||
const Communication& comm,
|
||||
std::size_t pressureEqnIndex,
|
||||
const Vector& weights,
|
||||
const Opm::CPRParameter& param)
|
||||
{
|
||||
using Matrix = typename Operator::matrix_type;
|
||||
using Block = typename Matrix::block_type;
|
||||
using BlockVector = typename Vector::block_type;
|
||||
std::unique_ptr<Matrix> matrix(new Matrix(op.getmat()));
|
||||
if (param.cpr_use_drs_) {
|
||||
const auto endi = matrix->end();
|
||||
for (auto i = matrix->begin(); i != endi; ++i) {
|
||||
const BlockVector& bw = weights[i.index()];
|
||||
const auto endj = (*i).end();
|
||||
for (auto j = (*i).begin(); j != endj; ++j) {
|
||||
Block& block = *j;
|
||||
BlockVector& bvec = block[pressureEqnIndex];
|
||||
// should introduce limits which also change the weights
|
||||
block.mtv(bw, bvec);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix;//, createOperator(op, *matrix, comm));
|
||||
}
|
||||
}
|
||||
|
||||
template<class Operator, class Criterion, class Communication, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
|
||||
class OneComponentAggregationLevelTransferPolicyCpr;
|
||||
|
||||
template<class Operator, class Criterion, class Communication, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
|
||||
class OneComponentAggregationLevelTransferPolicyCpr
|
||||
: public Dune::Amg::LevelTransferPolicyCpr<Operator, typename Detail::ScalarType<Operator>::value>
|
||||
{
|
||||
typedef Dune::Amg::AggregatesMap<typename Operator::matrix_type::size_type> AggregatesMap;
|
||||
public:
|
||||
using CoarseOperator = typename Detail::ScalarType<Operator>::value;
|
||||
typedef Dune::Amg::LevelTransferPolicy<Operator,CoarseOperator> FatherType;
|
||||
typedef Communication ParallelInformation;
|
||||
|
||||
public:
|
||||
OneComponentAggregationLevelTransferPolicyCpr(const Criterion& crit, const Communication& comm)
|
||||
: criterion_(crit), communication_(&const_cast<Communication&>(comm))
|
||||
{}
|
||||
|
||||
void createCoarseLevelSystem(const Operator& fineOperator)
|
||||
{
|
||||
prolongDamp_ = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
auto coarseRow = coarseLevelMatrix_->begin();
|
||||
for ( const auto& row: fineLevelMatrix )
|
||||
{
|
||||
auto coarseCol = coarseRow->begin();
|
||||
|
||||
for ( auto col = row.begin(), cend = row.end(); col != cend; ++col, ++coarseCol )
|
||||
{
|
||||
assert( col.index() == coarseCol.index() );
|
||||
*coarseCol = (*col)[COMPONENT_INDEX][VARIABLE_INDEX];
|
||||
}
|
||||
++coarseRow;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
// compleately unsafe!!!!!!
|
||||
void calculateCoarseEntries(const Operator& fineOperator)//const M& fineMatrix)
|
||||
{
|
||||
const auto& fineMatrix = fineOperator.getmat();
|
||||
*coarseLevelMatrix_ = 0;
|
||||
for(auto row = fineMatrix.begin(), rowEnd = fineMatrix.end();
|
||||
row != rowEnd; ++row)
|
||||
{
|
||||
const auto& i = row.index();
|
||||
for(auto entry = row->begin(), entryEnd = row->end();
|
||||
entry != entryEnd; ++entry)
|
||||
{
|
||||
const auto& j = entry.index();
|
||||
(*coarseLevelMatrix_)[i][j] += (*entry)[COMPONENT_INDEX][VARIABLE_INDEX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//template<class M>
|
||||
// void calculateCoarseEntriesOld(const Operator& fineOperator)//const M& fineMatrix)
|
||||
// {
|
||||
// const auto& fineMatrix = fineOperator.getmat();
|
||||
// *coarseLevelMatrix_ = 0;
|
||||
// for(auto row = fineMatrix.begin(), rowEnd = fineMatrix.end();
|
||||
// row != rowEnd; ++row)
|
||||
// {
|
||||
// const auto& i = (*aggregatesMap_)[row.index()];
|
||||
// if(i != AggregatesMap::ISOLATED)
|
||||
// {
|
||||
// for(auto entry = row->begin(), entryEnd = row->end();
|
||||
// entry != entryEnd; ++entry)
|
||||
// {
|
||||
// const auto& j = (*aggregatesMap_)[entry.index()];
|
||||
// if ( j != AggregatesMap::ISOLATED )
|
||||
// {
|
||||
// (*coarseLevelMatrix_)[i][j] += (*entry)[COMPONENT_INDEX][COMPONENT_INDEX];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
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)
|
||||
{
|
||||
this->rhs_[block-begin] = (*block)[COMPONENT_INDEX];
|
||||
}
|
||||
|
||||
|
||||
this->lhs_=0;
|
||||
}
|
||||
|
||||
void moveToFineLevel(typename FatherType::FineDomainType& fine)
|
||||
{
|
||||
|
||||
auto end=fine.end(), begin=fine.begin();
|
||||
|
||||
for(auto block=begin; block != end; ++block)
|
||||
{
|
||||
(*block)[COMPONENT_INDEX] = this->lhs_[block-begin];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OneComponentAggregationLevelTransferPolicyCpr* clone() const
|
||||
{
|
||||
return new OneComponentAggregationLevelTransferPolicyCpr(*this);
|
||||
}
|
||||
|
||||
const Communication& getCoarseLevelCommunication() const
|
||||
{
|
||||
return *coarseLevelCommunication_;
|
||||
}
|
||||
private:
|
||||
typename Operator::matrix_type::field_type prolongDamp_;
|
||||
//std::shared_ptr<AggregatesMap> aggregatesMap_;
|
||||
Criterion criterion_;
|
||||
Communication* communication_;
|
||||
std::shared_ptr<Communication> coarseLevelCommunication_;
|
||||
std::shared_ptr<typename CoarseOperator::matrix_type> coarseLevelMatrix_;
|
||||
};
|
||||
|
||||
namespace Detail
|
||||
{
|
||||
/**
|
||||
* @brief A policy class for solving the coarse level system using one step of AMG.
|
||||
* @tparam O The type of the linear operator used.
|
||||
* @tparam S The type of the smoother used in AMG.
|
||||
* @tparam C The type of the crition used for the aggregation within AMG.
|
||||
* @tparam C1 The type of the information about the communication. Either
|
||||
* Dune::OwnerOverlapCopyCommunication or Dune::SequentialInformation.
|
||||
*/
|
||||
template<class O, class S, class C, class P>
|
||||
class OneStepAMGCoarseSolverPolicyNoSolve
|
||||
{
|
||||
public:
|
||||
typedef P LevelTransferPolicy;
|
||||
/** @brief The type of the linear operator used. */
|
||||
typedef O Operator;
|
||||
/** @brief The type of the range and domain of the operator. */
|
||||
typedef typename O::range_type X;
|
||||
/** @brief The type of the crition used for the aggregation within AMG.*/
|
||||
typedef C Criterion;
|
||||
/** @brief The type of the communication used for AMG.*/
|
||||
typedef typename P::ParallelInformation Communication;
|
||||
/** @brief The type of the smoother used in AMG. */
|
||||
typedef S Smoother;
|
||||
/** @brief The type of the arguments used for constructing the smoother. */
|
||||
typedef typename Dune::Amg::SmootherTraits<S>::Arguments SmootherArgs;
|
||||
/** @brief The type of the AMG construct on the coarse level.*/
|
||||
typedef Dune::Amg::AMGCPR<Operator,X,Smoother,Communication> AMGType;
|
||||
/**
|
||||
* @brief Constructs the coarse solver policy.
|
||||
* @param args The arguments used for constructing the smoother.
|
||||
* @param c The crition used for the aggregation within AMG.
|
||||
*/
|
||||
OneStepAMGCoarseSolverPolicyNoSolve(const CPRParameter* param, const SmootherArgs& args, const Criterion& c)
|
||||
: param_(param), smootherArgs_(args), criterion_(c)
|
||||
{}
|
||||
/** @brief Copy constructor. */
|
||||
OneStepAMGCoarseSolverPolicyNoSolve(const OneStepAMGCoarseSolverPolicyNoSolve& other)
|
||||
: param_(other.param_), coarseOperator_(other.coarseOperator_), smootherArgs_(other.smootherArgs_),
|
||||
criterion_(other.criterion_)
|
||||
{}
|
||||
private:
|
||||
/**
|
||||
* @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 AMGInverseOperator : public Dune::InverseOperator<X,X>
|
||||
{
|
||||
AMGInverseOperator(const CPRParameter* param,
|
||||
typename AMGType::Operator& op,
|
||||
const Criterion& crit,
|
||||
const typename AMGType::SmootherArgs& args,
|
||||
const Communication& comm)
|
||||
: param_(param), amg_(),crit_(crit), op_(op),args_(args), comm_(comm)
|
||||
{
|
||||
amg_.reset(new AMGType(op, crit,args, comm));
|
||||
}
|
||||
|
||||
void updateAmgPreconditioner(typename AMGType::Operator& op){
|
||||
//op_ = op;
|
||||
//amg_->recalculateHierarchy();
|
||||
amg_->updateSolver(crit_, op, comm_);
|
||||
//amg_.reset(new AMGType(op, crit_,args_, comm_));
|
||||
//amg_->recalculateGalerkin();
|
||||
}
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
Dune::SolverCategory::Category category() const override
|
||||
{
|
||||
return std::is_same<Communication, Dune::Amg::SequentialInformation>::value ?
|
||||
Dune::SolverCategory::sequential : Dune::SolverCategory::overlapping;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void apply(X& x, X& b, double reduction, Dune::InverseOperatorResult& res)
|
||||
{
|
||||
DUNE_UNUSED_PARAMETER(reduction);
|
||||
DUNE_UNUSED_PARAMETER(res);
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
auto sp = Dune::createScalarProduct<X,Communication>(comm_, op_.category());
|
||||
#else
|
||||
using Chooser = Dune::ScalarProductChooser<X,Communication,AMGType::category>;
|
||||
auto sp = Chooser::construct(comm_);
|
||||
#endif
|
||||
Dune::Preconditioner<X,X>* prec = amg_.get();
|
||||
// Linear solver parameters
|
||||
const double tolerance = param_->cpr_solver_tol_;
|
||||
const int maxit = param_->cpr_max_ell_iter_;
|
||||
const int verbosity = ( param_->cpr_solver_verbose_ &&
|
||||
comm_.communicator().rank()==0 ) ? 1 : 0;
|
||||
if ( param_->cpr_ell_solvetype_ == 0 )
|
||||
{
|
||||
// Category of preconditioner will be checked at compile time. Therefore we need
|
||||
// to cast to the derived class
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
Dune::BiCGSTABSolver<X> solver(const_cast<typename AMGType::Operator&>(op_), *sp, *prec,
|
||||
tolerance, maxit, verbosity);
|
||||
#else
|
||||
Dune::BiCGSTABSolver<X> solver(const_cast<typename AMGType::Operator&>(op_), *sp,
|
||||
reinterpret_cast<AMGType&>(*prec),
|
||||
tolerance, maxit, verbosity);
|
||||
#endif
|
||||
solver.apply(x,b,res);
|
||||
|
||||
}
|
||||
else if (param_->cpr_ell_solvetype_ == 1)
|
||||
{
|
||||
// Category of preconditioner will be checked at compile time. Therefore we need
|
||||
// to cast to the derived class
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
Dune::CGSolver<X> solver(const_cast<typename AMGType::Operator&>(op_), *sp, *prec,
|
||||
tolerance, maxit, verbosity);
|
||||
#else
|
||||
Dune::CGSolver<X> solver(const_cast<typename AMGType::Operator&>(op_), *sp,
|
||||
reinterpret_cast<AMGType&>(*prec),
|
||||
tolerance, maxit, verbosity);
|
||||
#endif
|
||||
solver.apply(x,b,res);
|
||||
}
|
||||
else
|
||||
{
|
||||
// X v(x);
|
||||
// prec->pre(x,b);
|
||||
// op_->applyscaleadd(-1,x,b);
|
||||
// v = 0;
|
||||
// prec->apply(v,b);
|
||||
// x += v;
|
||||
// op_->applyscaleadd(-1,x,b);
|
||||
// prec->post(x);
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
Dune::LoopSolver<X> solver(const_cast<typename AMGType::Operator&>(op_), *sp, *prec,
|
||||
tolerance, maxit, verbosity);
|
||||
#else
|
||||
Dune::LoopSolver<X> solver(const_cast<typename AMGType::Operator&>(op_), *sp,
|
||||
reinterpret_cast<AMGType&>(*prec),
|
||||
tolerance, maxit, verbosity);
|
||||
#endif
|
||||
solver.apply(x,b,res);
|
||||
}
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
|
||||
#else
|
||||
delete sp;
|
||||
#endif
|
||||
}
|
||||
|
||||
void apply(X& x, X& b, Dune::InverseOperatorResult& res)
|
||||
{
|
||||
return apply(x,b,1e-8,res);
|
||||
}
|
||||
|
||||
~AMGInverseOperator()
|
||||
{}
|
||||
AMGInverseOperator(const AMGInverseOperator& other)
|
||||
: x_(other.x_), amg_(other.amg_)
|
||||
{
|
||||
}
|
||||
private:
|
||||
const CPRParameter* param_;
|
||||
X x_;
|
||||
std::unique_ptr<AMGType> amg_;
|
||||
//std::unique_ptr<typename AMGType::Operator> op_;
|
||||
typename AMGType::Operator& op_;
|
||||
Criterion crit_;
|
||||
typename AMGType::SmootherArgs args_;
|
||||
const Communication& comm_;
|
||||
};
|
||||
|
||||
public:
|
||||
/** @brief The type of solver constructed for the coarse level. */
|
||||
typedef AMGInverseOperator CoarseLevelSolver;
|
||||
|
||||
/**
|
||||
* @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();
|
||||
const LevelTransferPolicy& transfer =
|
||||
reinterpret_cast<const LevelTransferPolicy&>(transferPolicy);
|
||||
AMGInverseOperator* inv = new AMGInverseOperator(param_,
|
||||
*coarseOperator_,
|
||||
criterion_,
|
||||
smootherArgs_,
|
||||
transfer.getCoarseLevelCommunication());
|
||||
|
||||
return inv; //std::shared_ptr<InverseOperator<X,X> >(inv);
|
||||
|
||||
}
|
||||
//void recalculateGalerkin(){
|
||||
// coarseOperator_.recalculateHierarchy();
|
||||
//}
|
||||
private:
|
||||
/** @brief The coarse level operator. */
|
||||
std::shared_ptr<Operator> coarseOperator_;
|
||||
/** @brief The parameters for the CPR preconditioner. */
|
||||
const CPRParameter* param_;
|
||||
/** @brief The arguments used to construct the smoother. */
|
||||
SmootherArgs smootherArgs_;
|
||||
/** @brief The coarsening criterion. */
|
||||
Criterion criterion_;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Detail
|
||||
|
||||
|
||||
/**
|
||||
* \brief An algebraic twolevel or multigrid approach for solving blackoil (supports CPR with and without AMG)
|
||||
*
|
||||
* This preconditioner first decouples the component used for coarsening using a simple scaling
|
||||
* approach (e.g. Scheichl, Masson 2013,\see scaleMatrixDRS). Then it constructs the first
|
||||
* coarse level system, either by simply extracting the coupling between the components at COMPONENT_INDEX
|
||||
* in the matrix blocks or by extracting them and applying aggregation to them directly. This coarse level
|
||||
* can be solved either by AMG or by ILU. The preconditioner is configured using CPRParameter.
|
||||
* \tparam O The type of the operator (encapsulating a BCRSMatrix).
|
||||
* \tparam S The type of the smoother.
|
||||
* \tparam C The type of coarsening criterion to use.
|
||||
* \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).
|
||||
*/
|
||||
template<typename O, typename S, typename SC, typename C,
|
||||
typename P, std::size_t COMPONENT_INDEX, std::size_t VARIABLE_INDEX>
|
||||
class BlackoilAmgCpr
|
||||
: public Dune::Preconditioner<typename O::domain_type, typename O::range_type>
|
||||
{
|
||||
public:
|
||||
/** \brief The type of the operator (encapsulating a BCRSMatrix). */
|
||||
using Operator = O;
|
||||
/** \brief The type of coarsening criterion to use. */
|
||||
using Criterion = C;
|
||||
/** \brief The type of the class describing the parallelization. */
|
||||
using Communication = P;
|
||||
/** \brief The type of the smoother. */
|
||||
using Smoother = S;
|
||||
/** \brief The type of the smoother arguments for construction. */
|
||||
using SmootherArgs = typename Dune::Amg::SmootherTraits<Smoother>::Arguments;
|
||||
|
||||
protected:
|
||||
using Matrix = typename Operator::matrix_type;
|
||||
using CoarseOperator = typename Detail::ScalarType<Operator>::value;
|
||||
//using CoarseSmoother = typename Detail::ScalarType<Smoother>::value;
|
||||
using CoarseSmoother = typename Detail::ScalarType<SC>::value;
|
||||
using FineCriterion =
|
||||
typename Detail::OneComponentCriterionType<Criterion,COMPONENT_INDEX, VARIABLE_INDEX>::value;
|
||||
using CoarseCriterion = typename Detail::ScalarType<Criterion>::value;
|
||||
using LevelTransferPolicy =
|
||||
OneComponentAggregationLevelTransferPolicyCpr<Operator,
|
||||
FineCriterion,
|
||||
Communication,
|
||||
COMPONENT_INDEX,
|
||||
VARIABLE_INDEX>;
|
||||
using CoarseSolverPolicy =
|
||||
Detail::OneStepAMGCoarseSolverPolicyNoSolve<CoarseOperator,
|
||||
CoarseSmoother,
|
||||
CoarseCriterion,
|
||||
LevelTransferPolicy>;
|
||||
using TwoLevelMethod =
|
||||
Dune::Amg::TwoLevelMethodCpr<Operator,
|
||||
CoarseSolverPolicy,
|
||||
Smoother>;
|
||||
public:
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
Dune::SolverCategory::Category category() const override
|
||||
{
|
||||
return std::is_same<Communication, Dune::Amg::SequentialInformation>::value ?
|
||||
Dune::SolverCategory::sequential : Dune::SolverCategory::overlapping;
|
||||
}
|
||||
#else
|
||||
// define the category
|
||||
enum {
|
||||
//! \brief The category the precondtioner is part of.
|
||||
category = Operator::category
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Constructor.
|
||||
* \param param The parameters used for configuring the solver.
|
||||
* \param fineOperator The operator of the fine level.
|
||||
* \param criterion The criterion describing the coarsening approach.
|
||||
* \param smargs The arguments for constructing the smoother.
|
||||
* \param comm The information about the parallelization.
|
||||
*/
|
||||
BlackoilAmgCpr(const CPRParameter& param,
|
||||
const typename TwoLevelMethod::FineDomainType& weights,
|
||||
const Operator& fineOperator, const Criterion& criterion,
|
||||
const SmootherArgs& smargs, const Communication& comm)
|
||||
: param_(param),
|
||||
weights_(weights),
|
||||
scaledMatrix_(Detail::scaleMatrixDRSPtr(fineOperator, comm,
|
||||
COMPONENT_INDEX, weights_, param)),
|
||||
scaledMatrixOperator_(Detail::createOperatorPtr(fineOperator, *scaledMatrix_, comm)),
|
||||
smoother_(Detail::constructSmoother<Smoother>(*scaledMatrixOperator_,
|
||||
smargs, comm)),
|
||||
levelTransferPolicy_(criterion, comm),
|
||||
coarseSolverPolicy_(¶m, smargs, criterion),
|
||||
twoLevelMethod_(*scaledMatrixOperator_,
|
||||
smoother_,
|
||||
levelTransferPolicy_,
|
||||
coarseSolverPolicy_, 0, 1)
|
||||
{
|
||||
}
|
||||
void updatePreconditioner(const typename TwoLevelMethod::FineDomainType& weights,
|
||||
const Operator& fineOperator,
|
||||
const SmootherArgs& smargs,
|
||||
const Communication& comm){
|
||||
weights_ = weights;
|
||||
*scaledMatrix_ = *Detail::scaleMatrixDRSPtr(fineOperator, comm,
|
||||
COMPONENT_INDEX, weights_, param_);
|
||||
//*scaledMatrixOperator_ = *Detail::createOperatorPtr(fineOperator,*scaledMatrix_,comm);
|
||||
smoother_ .reset(Detail::constructSmoother<Smoother>(*scaledMatrixOperator_,
|
||||
smargs, comm));
|
||||
twoLevelMethod_.updatePreconditioner(*scaledMatrixOperator_,
|
||||
smoother_,
|
||||
coarseSolverPolicy_);
|
||||
}
|
||||
|
||||
void pre(typename TwoLevelMethod::FineDomainType& x,
|
||||
typename TwoLevelMethod::FineRangeType& b)
|
||||
{
|
||||
twoLevelMethod_.pre(x,b);
|
||||
}
|
||||
|
||||
void post(typename TwoLevelMethod::FineDomainType& x)
|
||||
{
|
||||
twoLevelMethod_.post(x);
|
||||
}
|
||||
|
||||
void apply(typename TwoLevelMethod::FineDomainType& v,
|
||||
const typename TwoLevelMethod::FineRangeType& d)
|
||||
{
|
||||
auto scaledD = d;
|
||||
Detail::scaleVectorDRS(scaledD, COMPONENT_INDEX, param_, weights_);
|
||||
twoLevelMethod_.apply(v, scaledD);
|
||||
}
|
||||
private:
|
||||
const CPRParameter& param_;
|
||||
//const typename TwoLevelMethod::FineDomainType& weights_;
|
||||
typename TwoLevelMethod::FineDomainType weights_;//make copy
|
||||
std::unique_ptr<Matrix> scaledMatrix_;
|
||||
std::unique_ptr<Operator> scaledMatrixOperator_;
|
||||
//Operator scaledMatrixOperator_;
|
||||
//std::tuple<std::unique_ptr<Matrix>, Operator>
|
||||
std::shared_ptr<Smoother> smoother_;
|
||||
LevelTransferPolicy levelTransferPolicy_;
|
||||
CoarseSolverPolicy coarseSolverPolicy_;
|
||||
TwoLevelMethod twoLevelMethod_;
|
||||
//BlockVector weights_;
|
||||
};
|
||||
|
||||
} // end namespace Opm
|
||||
#endif
|
350
opm/autodiff/ISTLSolverEbosCpr.hpp
Normal file
350
opm/autodiff/ISTLSolverEbosCpr.hpp
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
Copyright 2016 IRIS AS
|
||||
|
||||
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_ISTLSOLVERCPR_EBOS_HEADER_INCLUDED
|
||||
#define OPM_ISTLSOLVERCPR_EBOS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/autodiff/ISTLSolverEbos.hpp>
|
||||
#include <opm/autodiff/BlackoilAmgCpr.hpp>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
BEGIN_PROPERTIES
|
||||
NEW_PROP_TAG(CprSmootherFine);
|
||||
NEW_PROP_TAG(CprSmootherCoarse);
|
||||
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 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>
|
||||
class ISTLSolverEbosCpr : public ISTLSolverEbos<TypeTag>
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter) SparseMatrixAdapter;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) Vector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, EclWellModel) WellModel;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename SparseMatrixAdapter::IstlMatrix Matrix;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, CprSmootherFine) CprSmootherFine;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, CprSmootherCoarse) CprSmootherCoarse;
|
||||
//typedef typename SparseMatrixAdapter::MatrixBlock MatrixBlockType;
|
||||
//typedef typename Vector::block_type BlockVector;
|
||||
//typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
//typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager;
|
||||
//typedef typename GridView::template Codim<0>::Entity Element;
|
||||
//typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
|
||||
enum { pressureEqnIndex = BlackOilDefaultIndexTraits::waterCompIdx };
|
||||
enum { pressureVarIndex = Indices::pressureSwitchIdx };
|
||||
|
||||
static const int numEq = Indices::numEq;
|
||||
typedef WellModelMatrixAdapter< Matrix, Vector, Vector, WellModel, false> OperatorSerial;
|
||||
typedef ISTLSolverEbos<TypeTag> SuperClass;
|
||||
typedef Dune::Amg::SequentialInformation POrComm;
|
||||
//typedef ISTLUtility::CPRSelector< Matrix, Vector, Vector, POrComm> CPRSelectorType;
|
||||
typedef Dune::MatrixAdapter<Matrix,Vector, Vector> MatrixAdapter;
|
||||
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
|
||||
#else
|
||||
static constexpr int category = Dune::SolverCategory::sequential;
|
||||
typedef Dune::ScalarProductChooser<Vector, POrComm, category> ScalarProductChooser;
|
||||
#endif
|
||||
//Operator MatrixOperator = Dune::MatrixAdapter<Matrix,Vector,Vector>
|
||||
//typedef Opm::ParallelOverlappingILU0<Matrix,Vector,Vector, POrComm> Smoother;
|
||||
typedef CprSmootherFine Smoother;
|
||||
//ParallelInformation = Dune::Amg::SequentialInformation
|
||||
//typedef Dune::Amg::AMG<MatrixAdapter,Vector,Smoother,POrComm> DuneAmg;
|
||||
using CouplingMetric = Opm::Amg::Element<pressureEqnIndex,pressureVarIndex>;
|
||||
using CritBase = Dune::Amg::SymmetricCriterion<Matrix, CouplingMetric>;
|
||||
using Criterion = Dune::Amg::CoarsenCriterion<CritBase>;
|
||||
typedef BlackoilAmgCpr<MatrixAdapter,CprSmootherFine, CprSmootherCoarse, Criterion, POrComm, pressureEqnIndex, pressureVarIndex> BLACKOILAMG;
|
||||
|
||||
|
||||
public:
|
||||
typedef Dune::AssembledLinearOperator< Matrix, Vector, Vector > AssembledLinearOperatorType;
|
||||
|
||||
static void registerParameters()
|
||||
{
|
||||
FlowLinearSolverParameters::registerParameters<TypeTag>();
|
||||
}
|
||||
|
||||
/// Construct a system solver.
|
||||
/// \param[in] parallelInformation In the case of a parallel run
|
||||
/// with dune-istl the information about the parallelization.
|
||||
ISTLSolverEbosCpr(const Simulator& simulator)
|
||||
: SuperClass(simulator)
|
||||
{
|
||||
}
|
||||
|
||||
// nothing to clean here
|
||||
void eraseMatrix() {
|
||||
this->matrix_for_preconditioner_.reset();
|
||||
}
|
||||
|
||||
void prepare(const SparseMatrixAdapter& M, Vector& b){
|
||||
int newton_iteration = this->simulator_.model().newtonMethod().numIterations();
|
||||
// double dt = this->simulator_.timeStepSize();
|
||||
if( newton_iteration < 1 or not(this->parameters_.cpr_reuse_setup_) ){
|
||||
SuperClass::matrix_.reset(new Matrix(M.istlMatrix()));
|
||||
}else{
|
||||
*SuperClass::matrix_ = M.istlMatrix();
|
||||
}
|
||||
SuperClass::rhs_ = &b;
|
||||
SuperClass::scaleSystem();
|
||||
const WellModel& wellModel = this->simulator_.problem().wellModel();
|
||||
|
||||
#if HAVE_MPI
|
||||
if( this->isParallel() )
|
||||
{
|
||||
// parallel implemantation si as before
|
||||
// typedef WellModelMatrixAdapter< Matrix, Vector, Vector, WellModel, true ,TypeTag> Operator;
|
||||
|
||||
// auto ebosJacIgnoreOverlap = Matrix(*(this->matrix_));
|
||||
// //remove ghost rows in local matrix
|
||||
// this->makeOverlapRowsInvalid(ebosJacIgnoreOverlap);
|
||||
|
||||
// //Not sure what actual_mat_for_prec is, so put ebosJacIgnoreOverlap as both variables
|
||||
// //to be certain that correct matrix is used for preconditioning.
|
||||
// Operator opA(ebosJacIgnoreOverlap, ebosJacIgnoreOverlap, wellModel,
|
||||
// this->parallelInformation_ );
|
||||
// assert( opA.comm() );
|
||||
// //SuperClass::solve( opA, x, *(this->rhs_), *(opA.comm()) );
|
||||
// typedef Dune::OwnerOverlapCopyCommunication<int,int>& comm = *(opA.comm());
|
||||
// const size_t size = opA.getmat().N();
|
||||
|
||||
// const ParallelISTLInformation& info =
|
||||
// boost::any_cast<const ParallelISTLInformation&>( this->parallelInformation_);
|
||||
|
||||
// // As we use a dune-istl with block size np the number of components
|
||||
// // per parallel is only one.
|
||||
// info.copyValuesTo(comm.indexSet(), comm.remoteIndices(),
|
||||
// size, 1);
|
||||
// // Construct operator, scalar product and vectors needed.
|
||||
// Dune::InverseOperatorResult result;
|
||||
// SuperClass::constructPreconditionerAndSolve<Dune::SolverCategory::overlapping>(opA, x, *(this->rhs_), comm, result);
|
||||
// SuperClass::checkConvergence(result);
|
||||
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const WellModel& wellModel = this->simulator_.problem().wellModel();
|
||||
//typedef WellModelMatrixAdapter< Matrix, Vector, Vector, WellModel, false ,TypeTag> OperatorSerial;
|
||||
opASerial_.reset(new OperatorSerial(*(this->matrix_), *(this->matrix_), wellModel));
|
||||
|
||||
//Dune::Amg::SequentialInformation info;
|
||||
typedef Dune::Amg::SequentialInformation POrComm;
|
||||
POrComm parallelInformation_arg;
|
||||
typedef OperatorSerial LinearOperator;
|
||||
|
||||
//SuperClass::constructPreconditionerAndSolve(opA, x, *(this->rhs_), info, result);
|
||||
|
||||
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
constexpr Dune::SolverCategory::Category category=Dune::SolverCategory::sequential;
|
||||
auto sp = Dune::createScalarProduct<Vector,POrComm>(parallelInformation_arg, category);
|
||||
sp_ = std::move(sp);
|
||||
#else
|
||||
constexpr int category = Dune::SolverCategory::sequential;
|
||||
typedef Dune::ScalarProductChooser<Vector, POrComm, category> ScalarProductChooser;
|
||||
typedef std::unique_ptr<typename ScalarProductChooser::ScalarProduct> SPPointer;
|
||||
SPPointer sp(ScalarProductChooser::construct(parallelInformation_arg));
|
||||
sp_ = std::move(sp);
|
||||
#endif
|
||||
Vector& istlb = *(this->rhs_);
|
||||
parallelInformation_arg.copyOwnerToAll(istlb, istlb);
|
||||
|
||||
|
||||
|
||||
if( ! std::is_same< LinearOperator, MatrixAdapter > :: value )
|
||||
{
|
||||
// create new operator in case linear operator and matrix operator differ
|
||||
opA_.reset( new MatrixAdapter( opASerial_->getmat()));//, parallelInformation_arg ) );
|
||||
}
|
||||
|
||||
const double relax = this->parameters_.ilu_relaxation_;
|
||||
const MILU_VARIANT ilu_milu = this->parameters_.ilu_milu_;
|
||||
using Matrix = typename MatrixAdapter::matrix_type;
|
||||
//using CouplingMetric = Dune::Amg::Diagonal<pressureIndex>;
|
||||
//using CritBase = Dune::Amg::SymmetricCriterion<Matrix, CouplingMetric>;
|
||||
//using Criterion = Dune::Amg::CoarsenCriterion<CritBase>;
|
||||
//using AMG = typename ISTLUtility
|
||||
// ::BlackoilAmgSelector< Matrix, Vector, Vector,POrComm, Criterion, pressureIndex >::AMG;
|
||||
|
||||
//std::unique_ptr< AMG > amg;
|
||||
// Construct preconditioner.
|
||||
//Criterion crit(15, 2000);
|
||||
//SuperClass::constructAMGPrecond< Criterion >( linearOperator, parallelInformation_arg, amg, opA, relax, ilu_milu );
|
||||
// ISTLUtility::template createAMGPreconditionerPointer<Criterion>( *opA_,
|
||||
// relax,
|
||||
// parallelInformation_arg,
|
||||
// amg_,
|
||||
// this->parameters_,
|
||||
// this->weights_ );
|
||||
//using AMG = BlackoilAmg<Op,S,Criterion,P, PressureIndex>;
|
||||
POrComm& comm = parallelInformation_arg;
|
||||
const int verbosity = ( this->parameters_.cpr_solver_verbose_ &&
|
||||
comm.communicator().rank()==0 ) ? 1 : 0;
|
||||
|
||||
// TODO: revise choice of parameters
|
||||
//int coarsenTarget=4000;
|
||||
int coarsenTarget=1200;
|
||||
Criterion criterion(15, coarsenTarget);
|
||||
criterion.setDebugLevel( this->parameters_.cpr_solver_verbose_ ); // no debug information, 1 for printing hierarchy information
|
||||
criterion.setDefaultValuesIsotropic(2);
|
||||
criterion.setNoPostSmoothSteps( 1 );
|
||||
criterion.setNoPreSmoothSteps( 1 );
|
||||
//new guesses by hmbn
|
||||
//criterion.setAlpha(0.01); // criterion for connection strong 1/3 is default
|
||||
//criterion.setMaxLevel(2); //
|
||||
//criterion.setGamma(1); // //1 V cycle 2 WW
|
||||
|
||||
// Since DUNE 2.2 we also need to pass the smoother args instead of steps directly
|
||||
typedef typename BLACKOILAMG::Smoother Smoother;
|
||||
typedef typename BLACKOILAMG::Smoother Smoother;
|
||||
typedef typename Dune::Amg::SmootherTraits<Smoother>::Arguments SmootherArgs;
|
||||
SmootherArgs smootherArgs;
|
||||
smootherArgs.iterations = 1;
|
||||
smootherArgs.relaxationFactor = relax;
|
||||
const Opm::CPRParameter& params(this->parameters_); // strange conversion
|
||||
ISTLUtility::setILUParameters(smootherArgs, ilu_milu);
|
||||
//ISTLUtility::setILUParameters(smootherArgs, params);
|
||||
//smootherArgs.setN(params.cpr_ilu_n_); smootherArgs.setMilu(params.cpr_ilu_milu_);
|
||||
|
||||
MatrixAdapter& opARef = *opA_;
|
||||
int newton_iteration = this->simulator_.model().newtonMethod().numIterations();
|
||||
double dt = this->simulator_.timeStepSize();
|
||||
bool update_preconditioner = false;
|
||||
|
||||
if(this->parameters_.cpr_reuse_setup_ < 1){
|
||||
update_preconditioner = true;
|
||||
}
|
||||
if(this->parameters_.cpr_reuse_setup_ < 2){
|
||||
if(newton_iteration < 1){
|
||||
update_preconditioner = true;
|
||||
}
|
||||
}
|
||||
if(this->parameters_.cpr_reuse_setup_ < 3){
|
||||
if( this->iterations() > 10){
|
||||
update_preconditioner = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( update_preconditioner or (amg_== 0) ){
|
||||
amg_.reset( new BLACKOILAMG( params, this->weights_, opARef, criterion, smootherArgs, comm ) );
|
||||
}else{
|
||||
if(this->parameters_.cpr_solver_verbose_){
|
||||
std::cout << " Only update amg solver " << std::endl;
|
||||
}
|
||||
amg_->updatePreconditioner(this->weights_,opARef, smootherArgs, comm);
|
||||
}
|
||||
// Solve.
|
||||
//SuperClass::solve(linearOperator, x, istlb, *sp, *amg, result);
|
||||
//references seems to do something els than refering
|
||||
|
||||
int verbosity_linsolve = ( this->isIORank_ ) ? this->parameters_.linear_solver_verbosity_ : 0;
|
||||
LinearOperator& opASerialRef = *opASerial_;
|
||||
linsolve_.reset(new Dune::BiCGSTABSolver<Vector>(opASerialRef, *sp_, *amg_,
|
||||
this->parameters_.linear_solver_reduction_,
|
||||
this->parameters_.linear_solver_maxiter_,
|
||||
verbosity_linsolve));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool solve(Vector& x) {
|
||||
//SuperClass::solve(x);
|
||||
if( this->isParallel() ){
|
||||
// for now only call the superclass
|
||||
bool converged = SuperClass::solve(x);
|
||||
return converged;
|
||||
}else{
|
||||
// Solve system.
|
||||
Dune::InverseOperatorResult result;
|
||||
Vector& istlb = *(this->rhs_);
|
||||
linsolve_->apply(x, istlb, result);
|
||||
SuperClass::checkConvergence(result);
|
||||
|
||||
if(this->parameters_.scale_linear_system_){
|
||||
this->scaleSolution(x);
|
||||
}
|
||||
}
|
||||
return this->converged_;
|
||||
}
|
||||
|
||||
|
||||
/// Solve the system of linear equations Ax = b, with A being the
|
||||
/// combined derivative matrix of the residual and b
|
||||
/// being the residual itself.
|
||||
/// \param[in] residual residual object containing A and b.
|
||||
/// \return the solution x
|
||||
|
||||
/// \copydoc NewtonIterationBlackoilInterface::iterations
|
||||
int iterations () const { return this->iterations_; }
|
||||
|
||||
/// \copydoc NewtonIterationBlackoilInterface::parallelInformation
|
||||
const boost::any& parallelInformation() const { return this->parallelInformation_; }
|
||||
|
||||
protected:
|
||||
|
||||
//using Matrix = typename MatrixAdapter::matrix_type;
|
||||
//using CouplingMetric = Dune::Amg::Diagonal<pressureIndex>;
|
||||
//using CritBase = Dune::Amg::SymmetricCriterion<Matrix, CouplingMetric>;
|
||||
//using Criterion = Dune::Amg::CoarsenCriterion<CritBase>;
|
||||
//using AMG = typename ISTLUtility
|
||||
// ::BlackoilAmgSelector< Matrix, Vector, Vector,POrComm, Criterion, pressureIndex >::AMG;
|
||||
//Operator MatrixOperator = Dune::MatrixAdapter<Matrix,Vector,Vector>
|
||||
//Smoother ParallelOverLappingILU0<Matrix,Vector,Vector>
|
||||
//ParallelInformation = Dune::Amg::SequentialInformation
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
typedef std::shared_ptr< Dune::ScalarProduct<Vector> > SPPointer;
|
||||
#else
|
||||
typedef std::unique_ptr<typename ScalarProductChooser::ScalarProduct> SPPointer;
|
||||
#endif
|
||||
std::unique_ptr< MatrixAdapter > opA_;
|
||||
std::unique_ptr< OperatorSerial > opASerial_;
|
||||
std::unique_ptr< BLACKOILAMG > amg_;
|
||||
SPPointer sp_;
|
||||
std::shared_ptr< Dune::BiCGSTABSolver<Vector> > linsolve_;
|
||||
//std::shared_ptr< Dune::LinearOperator<Vector,Vector> > op_;
|
||||
//std::shared_ptr< Dune::Preconditioner<Vector,Vector> > prec_;
|
||||
//std::shared_ptr< Dune::ScalarProduct<Vector> > sp_;
|
||||
//Vector solution_;
|
||||
|
||||
}; // end ISTLSolver
|
||||
|
||||
} // namespace Opm
|
||||
#endif
|
1027
opm/autodiff/amgcpr.hh
Normal file
1027
opm/autodiff/amgcpr.hh
Normal file
File diff suppressed because it is too large
Load Diff
567
opm/autodiff/twolevelmethodcpr.hh
Normal file
567
opm/autodiff/twolevelmethodcpr.hh
Normal file
@ -0,0 +1,567 @@
|
||||
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
// vi: set et ts=4 sw=2 sts=2:
|
||||
#ifndef DUNE_ISTL_TWOLEVELMETHODCPR_HH
|
||||
#define DUNE_ISTL_TWOLEVELMETHODCPR_HH
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include<dune/istl/operators.hh>
|
||||
//#include "amg.hh"
|
||||
//#include"galerkin.hh"
|
||||
#include<dune/istl/paamg/amg.hh>
|
||||
#include<dune/istl/paamg/galerkin.hh>
|
||||
#include<dune/istl/solver.hh>
|
||||
|
||||
#include<dune/common/unused.hh>
|
||||
|
||||
/**
|
||||
* @addtogroup ISTL_PAAMG
|
||||
* @{
|
||||
* @file
|
||||
* @author Markus Blatt
|
||||
* @brief Algebraic twolevel methods.
|
||||
*/
|
||||
namespace Dune
|
||||
{
|
||||
namespace Amg
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Abstract base class for transfer between levels and creation
|
||||
* of the coarse level system.
|
||||
*
|
||||
* @tparam FO The type of the linear operator of the finel level system. Has to be
|
||||
* derived from AssembledLinearOperator.
|
||||
* @tparam CO The type of the linear operator of the coarse level system. Has to be
|
||||
* derived from AssembledLinearOperator.
|
||||
*/
|
||||
template<class FO, class CO>
|
||||
class LevelTransferPolicyCpr
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The linear operator of the finel level system. Has to be
|
||||
* derived from AssembledLinearOperator.
|
||||
*/
|
||||
typedef FO FineOperatorType;
|
||||
/**
|
||||
* @brief The type of the range of the fine level operator.
|
||||
*/
|
||||
typedef typename FineOperatorType::range_type FineRangeType;
|
||||
/**
|
||||
* @brief The type of the domain of the fine level operator.
|
||||
*/
|
||||
typedef typename FineOperatorType::domain_type FineDomainType;
|
||||
/**
|
||||
* @brief The linear operator of the finel level system. Has to be
|
||||
* derived from AssembledLinearOperator.
|
||||
*/
|
||||
typedef CO CoarseOperatorType;
|
||||
/**
|
||||
* @brief The type of the range of the coarse level operator.
|
||||
*/
|
||||
typedef typename CoarseOperatorType::range_type CoarseRangeType;
|
||||
/**
|
||||
* @brief The type of the domain of the coarse level operator.
|
||||
*/
|
||||
typedef typename CoarseOperatorType::domain_type CoarseDomainType;
|
||||
/**
|
||||
* @brief Get the coarse level operator.
|
||||
* @return A shared pointer to the coarse level system.
|
||||
*/
|
||||
std::shared_ptr<CoarseOperatorType>& getCoarseLevelOperator()
|
||||
{
|
||||
return operator_;
|
||||
}
|
||||
/**
|
||||
* @brief Get the coarse level right hand side.
|
||||
* @return The coarse level right hand side.
|
||||
*/
|
||||
CoarseRangeType& getCoarseLevelRhs()
|
||||
{
|
||||
return rhs_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the coarse level left hand side.
|
||||
* @return The coarse level leftt hand side.
|
||||
*/
|
||||
CoarseDomainType& getCoarseLevelLhs()
|
||||
{
|
||||
return lhs_;
|
||||
}
|
||||
/**
|
||||
* @brief Transfers the data to the coarse level.
|
||||
*
|
||||
* Restricts the residual to the right hand side of the
|
||||
* coarse level system and initialies the left hand side
|
||||
* of the coarse level system. These can afterwards be accessed
|
||||
* usinf getCoarseLevelRhs() and getCoarseLevelLhs().
|
||||
* @param fineDefect The current residual of the fine level system.
|
||||
*/
|
||||
virtual void moveToCoarseLevel(const FineRangeType& fineRhs)=0;
|
||||
/**
|
||||
* @brief Updates the fine level linear system after the correction
|
||||
* of the coarse levels system.
|
||||
*
|
||||
* After returning from this function the coarse level correction
|
||||
* will have been added to fine level system.
|
||||
* @param[inout] fineLhs The left hand side of the fine level to update
|
||||
* with the coarse level correction.
|
||||
*/
|
||||
virtual void moveToFineLevel(FineDomainType& fineLhs)=0;
|
||||
/**
|
||||
* @brief Algebraically creates the coarse level system.
|
||||
*
|
||||
* After returning from this function the coarse level operator
|
||||
* can be accessed using getCoarseLevelOperator().
|
||||
* @param fineOperator The operator of the fine level system.
|
||||
*/
|
||||
virtual void createCoarseLevelSystem(const FineOperatorType& fineOperator)=0;
|
||||
|
||||
//template<class M>
|
||||
virtual void calculateCoarseEntries(const FineOperatorType& fineOperator) = 0;
|
||||
//virtual void recalculateGalerkin(FineOperatorType& fineOperator)=0;
|
||||
|
||||
/** @brief Clone the current object. */
|
||||
virtual LevelTransferPolicyCpr* clone() const =0;
|
||||
|
||||
/** @brief Destructor. */
|
||||
virtual ~LevelTransferPolicyCpr(){}
|
||||
|
||||
protected:
|
||||
/** @brief The coarse level rhs. */
|
||||
CoarseRangeType rhs_;
|
||||
/** @brief The coarse level lhs. */
|
||||
CoarseDomainType lhs_;
|
||||
/** @brief the coarse level linear operator. */
|
||||
std::shared_ptr<CoarseOperatorType> operator_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A LeveTransferPolicy that used aggregation to construct the coarse level system.
|
||||
* @tparam O The type of the fine and coarse level operator.
|
||||
* @tparam C The criterion that describes the aggregation procedure.
|
||||
*/
|
||||
template<class O, class C>
|
||||
class AggregationLevelTransferPolicyCpr
|
||||
: public LevelTransferPolicyCpr<O,O>
|
||||
{
|
||||
typedef Dune::Amg::AggregatesMap<typename O::matrix_type::size_type> AggregatesMap;
|
||||
public:
|
||||
typedef LevelTransferPolicyCpr<O,O> FatherType;
|
||||
typedef C Criterion;
|
||||
typedef SequentialInformation ParallelInformation;
|
||||
|
||||
AggregationLevelTransferPolicyCpr(const Criterion& crit)
|
||||
: criterion_(crit)
|
||||
{}
|
||||
|
||||
void createCoarseLevelSystem(const O& fineOperator)
|
||||
{
|
||||
prolongDamp_ = criterion_.getProlongationDampingFactor();
|
||||
GalerkinProduct<ParallelInformation> productBuilder;
|
||||
typedef typename Dune::Amg::MatrixGraph<const typename O::matrix_type> MatrixGraph;
|
||||
typedef typename Dune::Amg::PropertiesGraph<MatrixGraph,Dune::Amg::VertexProperties,
|
||||
Dune::Amg::EdgeProperties,Dune::IdentityMap,Dune::IdentityMap> PropertiesGraph;
|
||||
MatrixGraph mg(fineOperator.getmat());
|
||||
PropertiesGraph pg(mg,Dune::IdentityMap(),Dune::IdentityMap());
|
||||
typedef NegateSet<typename ParallelInformation::OwnerSet> OverlapFlags;
|
||||
|
||||
aggregatesMap_.reset(new AggregatesMap(pg.maxVertex()+1));
|
||||
|
||||
int noAggregates, isoAggregates, oneAggregates, skippedAggregates;
|
||||
|
||||
std::tie(noAggregates, isoAggregates, oneAggregates, skippedAggregates) =
|
||||
aggregatesMap_->buildAggregates(fineOperator.getmat(), pg, criterion_, true);
|
||||
std::cout<<"no aggregates="<<noAggregates<<" iso="<<isoAggregates<<" one="<<oneAggregates<<" skipped="<<skippedAggregates<<std::endl;
|
||||
// misuse coarsener to renumber aggregates
|
||||
Dune::Amg::IndicesCoarsener<Dune::Amg::SequentialInformation,int> renumberer;
|
||||
typedef std::vector<bool>::iterator Iterator;
|
||||
typedef Dune::IteratorPropertyMap<Iterator, Dune::IdentityMap> VisitedMap;
|
||||
std::vector<bool> excluded(fineOperator.getmat().N(), false);
|
||||
VisitedMap vm(excluded.begin(), Dune::IdentityMap());
|
||||
ParallelInformation pinfo;
|
||||
std::size_t aggregates = renumberer.coarsen(pinfo, pg, vm,
|
||||
*aggregatesMap_, pinfo,
|
||||
noAggregates);
|
||||
std::vector<bool>& visited=excluded;
|
||||
|
||||
typedef std::vector<bool>::iterator Iterator;
|
||||
|
||||
for(Iterator iter= visited.begin(), end=visited.end();
|
||||
iter != end; ++iter)
|
||||
*iter=false;
|
||||
matrix_.reset(productBuilder.build(mg, vm,
|
||||
SequentialInformation(),
|
||||
*aggregatesMap_,
|
||||
aggregates,
|
||||
OverlapFlags()));
|
||||
productBuilder.calculate(fineOperator.getmat(), *aggregatesMap_, *matrix_, pinfo, OverlapFlags());
|
||||
this->lhs_.resize(this->matrix_->M());
|
||||
this->rhs_.resize(this->matrix_->N());
|
||||
this->operator_.reset(new O(*matrix_));
|
||||
}
|
||||
|
||||
void moveToCoarseLevel(const typename FatherType::FineRangeType& fineRhs)
|
||||
{
|
||||
Transfer<std::size_t,typename FatherType::FineRangeType,ParallelInformation>
|
||||
::restrictVector(*aggregatesMap_, this->rhs_, fineRhs, ParallelInformation());
|
||||
this->lhs_=0;
|
||||
}
|
||||
|
||||
void moveToFineLevel(typename FatherType::FineDomainType& fineLhs)
|
||||
{
|
||||
Transfer<std::size_t,typename FatherType::FineRangeType,ParallelInformation>
|
||||
::prolongateVector(*aggregatesMap_, this->lhs_, fineLhs,
|
||||
prolongDamp_, ParallelInformation());
|
||||
}
|
||||
|
||||
AggregationLevelTransferPolicyCpr* clone() const
|
||||
{
|
||||
return new AggregationLevelTransferPolicyCpr(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
typename O::matrix_type::field_type prolongDamp_;
|
||||
std::shared_ptr<AggregatesMap> aggregatesMap_;
|
||||
Criterion criterion_;
|
||||
std::shared_ptr<typename O::matrix_type> matrix_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A policy class for solving the coarse level system using one step of AMG.
|
||||
* @tparam O The type of the linear operator used.
|
||||
* @tparam S The type of the smoother used in AMG.
|
||||
* @tparam C The type of the crition used for the aggregation within AMG.
|
||||
*/
|
||||
template<class O, class S, class C>
|
||||
class OneStepAMGCoarseSolverPolicyCpr
|
||||
{
|
||||
public:
|
||||
/** @brief The type of the linear operator used. */
|
||||
typedef O Operator;
|
||||
/** @brief The type of the range and domain of the operator. */
|
||||
typedef typename O::range_type X;
|
||||
/** @brief The type of the crition used for the aggregation within AMG.*/
|
||||
typedef C Criterion;
|
||||
/** @brief The type of the smoother used in AMG. */
|
||||
typedef S Smoother;
|
||||
/** @brief The type of the arguments used for constructing the smoother. */
|
||||
typedef typename Dune::Amg::SmootherTraits<S>::Arguments SmootherArgs;
|
||||
/** @brief The type of the AMG construct on the coarse level.*/
|
||||
typedef AMG<Operator,X,Smoother> AMGType;
|
||||
/**
|
||||
* @brief Constructs the coarse solver policy.
|
||||
* @param args The arguments used for constructing the smoother.
|
||||
* @param c The crition used for the aggregation within AMG.
|
||||
*/
|
||||
OneStepAMGCoarseSolverPolicyCpr(const SmootherArgs& args, const Criterion& c)
|
||||
: smootherArgs_(args), criterion_(c)
|
||||
{}
|
||||
/** @brief Copy constructor. */
|
||||
OneStepAMGCoarseSolverPolicyCpr(const OneStepAMGCoarseSolverPolicyCpr& other)
|
||||
: coarseOperator_(other.coarseOperator_), smootherArgs_(other.smootherArgs_),
|
||||
criterion_(other.criterion_)
|
||||
{}
|
||||
private:
|
||||
/**
|
||||
* @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 AMGInverseOperator : public InverseOperator<X,X>
|
||||
{
|
||||
AMGInverseOperator(const typename AMGType::Operator& op,
|
||||
const Criterion& crit,
|
||||
const typename AMGType::SmootherArgs& args)
|
||||
: amg_(op, crit,args), first_(true)
|
||||
{}
|
||||
|
||||
void apply(X& x, X& b, double reduction, InverseOperatorResult& res)
|
||||
{
|
||||
DUNE_UNUSED_PARAMETER(reduction);
|
||||
DUNE_UNUSED_PARAMETER(res);
|
||||
if(first_)
|
||||
{
|
||||
amg_.pre(x,b);
|
||||
first_=false;
|
||||
x_=x;
|
||||
}
|
||||
amg_.apply(x,b);
|
||||
}
|
||||
|
||||
void apply(X& x, X& b, InverseOperatorResult& res)
|
||||
{
|
||||
return apply(x,b,1e-8,res);
|
||||
}
|
||||
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
virtual SolverCategory::Category category() const
|
||||
{
|
||||
return amg_.category();
|
||||
}
|
||||
#endif
|
||||
|
||||
~AMGInverseOperator()
|
||||
{
|
||||
if(!first_)
|
||||
amg_.post(x_);
|
||||
}
|
||||
AMGInverseOperator(const AMGInverseOperator& other)
|
||||
: x_(other.x_), amg_(other.amg_), first_(other.first_)
|
||||
{
|
||||
}
|
||||
private:
|
||||
X x_;
|
||||
AMGType amg_;
|
||||
bool first_;
|
||||
};
|
||||
|
||||
public:
|
||||
/** @brief The type of solver constructed for the coarse level. */
|
||||
typedef AMGInverseOperator CoarseLevelSolver;
|
||||
|
||||
/**
|
||||
* @brief Constructs a coarse level solver.
|
||||
*
|
||||
* @param transferPolicy The policy describing the transfer between levels.
|
||||
* @return A pointer to the constructed coarse level solver.
|
||||
* @tparam P The type of the level transfer policy.
|
||||
*/
|
||||
template<class P>
|
||||
CoarseLevelSolver* createCoarseLevelSolver(P& transferPolicy)
|
||||
{
|
||||
coarseOperator_=transferPolicy.getCoarseLevelOperator();
|
||||
AMGInverseOperator* inv = new AMGInverseOperator(*coarseOperator_,
|
||||
criterion_,
|
||||
smootherArgs_);
|
||||
|
||||
return inv; //std::shared_ptr<InverseOperator<X,X> >(inv);
|
||||
|
||||
}
|
||||
//void recalculateGalerkin(){//coarseOperator){
|
||||
//coarseOperator_.resetOperator
|
||||
//coarseOperator_.recalculateHierarchy();
|
||||
//}
|
||||
private:
|
||||
/** @brief The coarse level operator. */
|
||||
std::shared_ptr<Operator> coarseOperator_;
|
||||
/** @brief The arguments used to construct the smoother. */
|
||||
SmootherArgs smootherArgs_;
|
||||
/** @brief The coarsening criterion. */
|
||||
Criterion criterion_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @tparam FO The type of the fine level linear operator.
|
||||
* @tparam CSP The type of the coarse level solver policy.
|
||||
* @tparam S The type of the fine level smoother used.
|
||||
*/
|
||||
template<class FO, class CSP, class S>
|
||||
class TwoLevelMethodCpr :
|
||||
public Preconditioner<typename FO::domain_type, typename FO::range_type>
|
||||
{
|
||||
public:
|
||||
/** @brief The type of the policy for constructing the coarse level solver. */
|
||||
typedef CSP CoarseLevelSolverPolicy;
|
||||
/** @brief The type of the coarse level solver. */
|
||||
typedef typename CoarseLevelSolverPolicy::CoarseLevelSolver CoarseLevelSolver;
|
||||
/**
|
||||
* @brief The linear operator of the finel level system. Has to be
|
||||
* derived from AssembledLinearOperator.
|
||||
*/
|
||||
typedef FO FineOperatorType;
|
||||
/**
|
||||
* @brief The type of the range of the fine level operator.
|
||||
*/
|
||||
typedef typename FineOperatorType::range_type FineRangeType;
|
||||
/**
|
||||
* @brief The type of the domain of the fine level operator.
|
||||
*/
|
||||
typedef typename FineOperatorType::domain_type FineDomainType;
|
||||
/**
|
||||
* @brief The linear operator of the finel level system. Has to be
|
||||
* derived from AssembledLinearOperator.
|
||||
*/
|
||||
typedef typename CSP::Operator CoarseOperatorType;
|
||||
/**
|
||||
* @brief The type of the range of the coarse level operator.
|
||||
*/
|
||||
typedef typename CoarseOperatorType::range_type CoarseRangeType;
|
||||
/**
|
||||
* @brief The type of the domain of the coarse level operator.
|
||||
*/
|
||||
typedef typename CoarseOperatorType::domain_type CoarseDomainType;
|
||||
/**
|
||||
* @brief The type of the fine level smoother.
|
||||
*/
|
||||
typedef S SmootherType;
|
||||
|
||||
// define the category
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
|
||||
#else
|
||||
enum {
|
||||
//! \brief The category the preconditioner is part of.
|
||||
category=SolverCategory::sequential
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Constructs a two level method.
|
||||
*
|
||||
* @tparam CoarseSolverPolicy The policy for constructing the coarse
|
||||
* solver, e.g. OneStepAMGCoarseSolverPolicy
|
||||
* @param op The fine level operator.
|
||||
* @param smoother The fine level smoother.
|
||||
* @param policy The level transfer policy.
|
||||
* @param coarsePolicy The policy for constructing the coarse level solver.
|
||||
* @param preSteps The number of smoothing steps to apply before the coarse
|
||||
* level correction.
|
||||
* @param preSteps The number of smoothing steps to apply after the coarse
|
||||
* level correction.
|
||||
*/
|
||||
TwoLevelMethodCpr(FineOperatorType& op,
|
||||
std::shared_ptr<SmootherType> smoother,
|
||||
const LevelTransferPolicyCpr<FineOperatorType,
|
||||
CoarseOperatorType>& policy,
|
||||
CoarseLevelSolverPolicy& coarsePolicy,
|
||||
std::size_t preSteps=1, std::size_t postSteps=1)
|
||||
: operator_(&op), smoother_(smoother),
|
||||
preSteps_(preSteps), postSteps_(postSteps)
|
||||
{
|
||||
policy_ = policy.clone();
|
||||
policy_->createCoarseLevelSystem(*operator_);
|
||||
coarseSolver_= coarsePolicy.createCoarseLevelSolver(*policy_);
|
||||
}
|
||||
|
||||
TwoLevelMethodCpr(const TwoLevelMethodCpr& other)
|
||||
: operator_(other.operator_), coarseSolver_(new CoarseLevelSolver(*other.coarseSolver_)),
|
||||
smoother_(other.smoother_), policy_(other.policy_->clone()),
|
||||
preSteps_(other.preSteps_), postSteps_(other.postSteps_)
|
||||
{}
|
||||
|
||||
~TwoLevelMethodCpr()
|
||||
{
|
||||
// Each instance has its own policy.
|
||||
delete policy_;
|
||||
delete coarseSolver_;
|
||||
}
|
||||
void updatePreconditioner(FineOperatorType& op,
|
||||
std::shared_ptr<SmootherType> smoother,
|
||||
CoarseLevelSolverPolicy& coarsePolicy){
|
||||
//assume new matrix is not reallocated the new precondition should anyway be made
|
||||
//operator_ = &op;// hope fine scale operator is the same
|
||||
smoother_ = smoother;
|
||||
if(not(coarseSolver_ == 0)){
|
||||
//delete coarseSolver_;
|
||||
//std::cout << " Only rebuild hirarchy " << std::endl;
|
||||
//policy_->createCoarseLevelSystem(*operator_);
|
||||
policy_->calculateCoarseEntries(*operator_);
|
||||
//policy_->calculateCoarseEntries(7);
|
||||
coarsePolicy.setCoarseOperator(*policy_);
|
||||
//delete coarseSolver_;
|
||||
//coarseSolver_ = coarsePolicy.createCoarseLevelSolver(*policy_);
|
||||
coarseSolver_->updateAmgPreconditioner(*(policy_->getCoarseLevelOperator()));
|
||||
}else{
|
||||
// we should probably not be heere
|
||||
policy_->createCoarseLevelSystem(*operator_);
|
||||
coarseSolver_ = coarsePolicy.createCoarseLevelSolver(*policy_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pre(FineDomainType& x, FineRangeType& b)
|
||||
{
|
||||
smoother_->pre(x,b);
|
||||
}
|
||||
|
||||
void post(FineDomainType& x)
|
||||
{
|
||||
DUNE_UNUSED_PARAMETER(x);
|
||||
}
|
||||
|
||||
void apply(FineDomainType& v, const FineRangeType& d)
|
||||
{
|
||||
FineDomainType u(v);
|
||||
FineRangeType rhs(d);
|
||||
LevelContext context;
|
||||
SequentialInformation info;
|
||||
context.pinfo=&info;
|
||||
context.lhs=&u;
|
||||
context.update=&v;
|
||||
context.smoother=smoother_;
|
||||
context.rhs=&rhs;
|
||||
context.matrix=operator_;
|
||||
// Presmoothing
|
||||
presmooth(context, preSteps_);
|
||||
//Coarse grid correction
|
||||
policy_->moveToCoarseLevel(*context.rhs);
|
||||
InverseOperatorResult res;
|
||||
coarseSolver_->apply(policy_->getCoarseLevelLhs(), policy_->getCoarseLevelRhs(), res);
|
||||
*context.lhs=0;
|
||||
policy_->moveToFineLevel(*context.lhs);
|
||||
*context.update += *context.lhs;
|
||||
// Postsmoothing
|
||||
postsmooth(context, postSteps_);
|
||||
|
||||
}
|
||||
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6)
|
||||
// //! Category of the preconditioner (see SolverCategory::Category)
|
||||
virtual SolverCategory::Category category() const
|
||||
{
|
||||
return SolverCategory::sequential;
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
/**
|
||||
* @brief Struct containing the level information.
|
||||
*/
|
||||
struct LevelContext
|
||||
{
|
||||
/** @brief The type of the smoother used. */
|
||||
typedef S SmootherType;
|
||||
/** @brief A pointer to the smoother. */
|
||||
std::shared_ptr<SmootherType> smoother;
|
||||
/** @brief The left hand side passed to the and returned by the smoother. */
|
||||
FineDomainType* lhs;
|
||||
/*
|
||||
* @brief The right hand side holding the current residual.
|
||||
*
|
||||
* This is passed to the smoother as the right hand side.
|
||||
*/
|
||||
FineRangeType* rhs;
|
||||
/**
|
||||
* @brief The total update calculated by the preconditioner.
|
||||
*
|
||||
* I.e. all update from smoothing and coarse grid correction summed up.
|
||||
*/
|
||||
FineDomainType* update;
|
||||
/** @parallel information */
|
||||
SequentialInformation* pinfo;
|
||||
/**
|
||||
* @brief The matrix that we are solving.
|
||||
*
|
||||
* Needed to update the residual.
|
||||
*/
|
||||
const FineOperatorType* matrix;
|
||||
};
|
||||
FineOperatorType* operator_;
|
||||
/** @brief The coarse level solver. */
|
||||
CoarseLevelSolver* coarseSolver_;
|
||||
/** @brief The fine level smoother. */
|
||||
std::shared_ptr<S> smoother_;
|
||||
/** @brief Policy for prolongation, restriction, and coarse level system creation. */
|
||||
LevelTransferPolicyCpr<FO,typename CSP::Operator>* policy_;
|
||||
/** @brief The number of presmoothing steps to apply. */
|
||||
std::size_t preSteps_;
|
||||
/** @brief The number of postsmoothing steps to apply. */
|
||||
std::size_t postSteps_;
|
||||
};
|
||||
}// end namespace Amg
|
||||
}// end namespace Dune
|
||||
|
||||
/** @} */
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user