/* 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 . */ #ifndef OPM_AMGCPR_HEADER_INCLUDED #define OPM_AMGCPR_HEADER_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Opm { /** * \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 * coarse level system. The coupling is defined by the weights corresponding to the element located at * (COMPONENT_INDEX, VARIABLE_INDEX) in the block matrix. Then the coarse level system is constructed * either by extracting these elements, or by 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 water). * \tparam VARIABLE_INDEX The index of the variable to use for coarsening (usually pressure). */ template class BlackoilAmgCpr : public Dune::Preconditioner { 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::Arguments; protected: using Matrix = typename Operator::matrix_type; using CoarseOperator = typename Detail::ScalarType::value; using CoarseSmoother = typename Detail::ScalarType::value; using FineCriterion = typename Detail::OneComponentCriterionType::value; using CoarseCriterion = typename Detail::ScalarType::value; using LevelTransferPolicy = OneComponentAggregationLevelTransferPolicy; using CoarseSolverPolicy = Detail::OneStepAMGCoarseSolverPolicy; using TwoLevelMethod = Dune::Amg::TwoLevelMethodCpr; public: #if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 6) Dune::SolverCategory::Category category() const override { return std::is_same::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::scaleMatrixDRS(fineOperator, COMPONENT_INDEX, weights_, param)), scaledMatrixOperator_(Detail::createOperator(fineOperator, *scaledMatrix_, comm)), smoother_(Detail::constructSmoother(*scaledMatrixOperator_, smargs, comm)), levelTransferPolicy_(criterion, comm, param.cpr_pressure_aggregation_), coarseSolverPolicy_(¶m, smargs, criterion), twoLevelMethod_(*scaledMatrixOperator_, smoother_, levelTransferPolicy_, coarseSolverPolicy_, 0, 1) { } void updatePreconditioner(const Operator& fineOperator, const SmootherArgs& smargs, const Communication& comm) { *scaledMatrix_ = *Detail::scaleMatrixDRS(fineOperator, COMPONENT_INDEX, weights_, param_); smoother_.reset(Detail::constructSmoother(*scaledMatrixOperator_, smargs, comm)); twoLevelMethod_.updatePreconditioner(*scaledMatrixOperator_, smoother_, coarseSolverPolicy_); } void pre(typename TwoLevelMethod::FineDomainType& x, typename TwoLevelMethod::FineRangeType& b) override { twoLevelMethod_.pre(x,b); } void post(typename TwoLevelMethod::FineDomainType& x) override { twoLevelMethod_.post(x); } void apply(typename TwoLevelMethod::FineDomainType& v, const typename TwoLevelMethod::FineRangeType& d) override { auto scaledD = d; Detail::scaleVectorDRS(scaledD, COMPONENT_INDEX, param_, weights_); twoLevelMethod_.apply(v, scaledD); } private: const CPRParameter& param_; const typename TwoLevelMethod::FineDomainType& weights_; std::unique_ptr scaledMatrix_; std::unique_ptr scaledMatrixOperator_; std::shared_ptr smoother_; LevelTransferPolicy levelTransferPolicy_; CoarseSolverPolicy coarseSolverPolicy_; TwoLevelMethod twoLevelMethod_; }; } // end namespace Opm #endif