22 #ifndef OPM_ISTLSOLVER_HEADER_INCLUDED 23 #define OPM_ISTLSOLVER_HEADER_INCLUDED 25 #include <dune/istl/owneroverlapcopy.hh> 26 #include <dune/istl/solver.hh> 28 #include <opm/common/CriticalError.hpp> 29 #include <opm/common/ErrorMacros.hpp> 30 #include <opm/common/Exceptions.hpp> 31 #include <opm/common/TimingMacros.hpp> 33 #include <opm/grid/utility/ElementChunks.hpp> 39 #include <opm/simulators/flow/BlackoilModelParameters.hpp> 42 #include <opm/simulators/linalg/ExtractParallelGridInformationToISTL.hpp> 43 #include <opm/simulators/linalg/FlowLinearSolverParameters.hpp> 44 #include <opm/simulators/linalg/matrixblock.hh> 46 #include <opm/simulators/linalg/PreconditionerWithUpdate.hpp> 47 #include <opm/simulators/linalg/WellOperators.hpp> 48 #include <opm/simulators/linalg/WriteSystemMatrixHelper.hpp> 49 #include <opm/simulators/linalg/findOverlapRowsAndColumns.hpp> 50 #include <opm/simulators/linalg/getQuasiImpesWeights.hpp> 51 #include <opm/simulators/linalg/setupPropertyTree.hpp> 52 #include <opm/simulators/linalg/AbstractISTLSolver.hpp> 53 #include <opm/simulators/linalg/printlinearsolverparameter.hpp> 55 #include <fmt/format.h> 71 using InheritsFrom = std::tuple<FlowIstlSolverParams>;
75 template <
class TypeTag,
class MyTypeTag>
80 template<
class TypeTag>
85 enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
101 template<
class Matrix,
class Vector,
class Comm>
104 using AbstractSolverType = Dune::InverseOperator<Vector, Vector>;
105 using AbstractOperatorType = Dune::AssembledLinearOperator<Matrix, Vector, Vector>;
108 void create(
const Matrix& matrix,
111 std::size_t pressureIndex,
112 std::function<Vector()> weightCalculator,
113 const bool forceSerial,
116 std::unique_ptr<AbstractSolverType> solver_;
117 std::unique_ptr<AbstractOperatorType> op_;
118 std::unique_ptr<LinearOperatorExtra<Vector,Vector>> wellOperator_;
120 std::size_t interiorCellNum_ = 0;
125 void copyParValues(std::any& parallelInformation, std::size_t size,
127 Dune::OwnerOverlapCopyCommunication<int,int>& comm);
132 template<
class Matrix>
133 void makeOverlapRowsInvalid(Matrix& matrix,
134 const std::vector<int>& overlapRows);
138 template<
class Matrix,
class Gr
id>
139 std::unique_ptr<Matrix> blockJacobiAdjacency(
const Grid& grid,
140 const std::vector<int>& cell_part,
141 std::size_t nonzeroes,
142 const std::vector<std::set<int>>& wellConnectionsGraph);
149 template <
class TypeTag>
151 GetPropType<TypeTag, Properties::GlobalEqVector>>
161 using Matrix =
typename SparseMatrixAdapter::IstlMatrix;
164 using AbstractSolverType = Dune::InverseOperator<Vector, Vector>;
165 using AbstractOperatorType = Dune::AssembledLinearOperator<Matrix, Vector, Vector>;
169 using ElementChunksType = ElementChunks<GridView, Dune::Partitions::All>;
173 static constexpr
bool enablePolymerMolarWeight = getPropValue<TypeTag, Properties::EnablePolymerMW>();
174 constexpr
static bool isIncompatibleWithCprw = enablePolymerMolarWeight;
177 using CommunicationType = Dune::OwnerOverlapCopyCommunication<int,int>;
179 using CommunicationType = Dune::Communication<int>;
183 using AssembledLinearOperatorType = Dune::AssembledLinearOperator< Matrix, Vector, Vector >;
185 static void registerParameters()
187 FlowLinearSolverParameters::registerParameters();
199 bool forceSerial =
false)
200 : simulator_(simulator),
203 parameters_{parameters},
204 forceSerial_(forceSerial)
212 : simulator_(simulator),
217 parameters_.resize(1);
218 parameters_[0].init(simulator_.vanguard().eclState().getSimulationConfig().useCPR());
224 OPM_TIMEBLOCK(IstlSolver);
226 if (isIncompatibleWithCprw) {
230 if (parameters_[0].linsolver_ ==
"cprw" || parameters_[0].linsolver_ ==
"hybrid") {
231 const bool on_io_rank = (simulator_.gridView().comm().rank() == 0);
232 const std::string msg =
233 fmt::format(
"The polymer injectivity model is incompatible with the '{}' " 234 "linear solver. Falling back to --linear-solver=ilu0.",
235 parameters_[0].linsolver_);
237 OpmLog::warning(msg);
239 parameters_[0].linsolver_ =
"ilu0";
243 if (parameters_[0].linsolver_ ==
"hybrid") {
251 FlowLinearSolverParameters para;
253 para.linsolver_ =
"cprw";
254 parameters_.push_back(para);
256 Parameters::IsSet<Parameters::LinearSolverMaxIter>(),
257 Parameters::IsSet<Parameters::LinearSolverReduction>()));
260 FlowLinearSolverParameters para;
262 para.linsolver_ =
"ilu0";
263 parameters_.push_back(para);
265 Parameters::IsSet<Parameters::LinearSolverMaxIter>(),
266 Parameters::IsSet<Parameters::LinearSolverReduction>()));
270 assert(parameters_.size() == 1);
271 assert(prm_.empty());
274 if (parameters_[0].is_nldd_local_solver_) {
276 Parameters::IsSet<Parameters::NlddLocalLinearSolverMaxIter>(),
277 Parameters::IsSet<Parameters::NlddLocalLinearSolverReduction>()));
281 Parameters::IsSet<Parameters::LinearSolverMaxIter>(),
282 Parameters::IsSet<Parameters::LinearSolverReduction>()));
285 flexibleSolver_.resize(prm_.size());
287 const bool on_io_rank = (simulator_.gridView().comm().rank() == 0);
289 comm_.reset(
new CommunicationType( simulator_.vanguard().grid().comm() ) );
296 ElementMapper elemMapper(simulator_.vanguard().gridView(), Dune::mcmgElementLayout());
297 detail::findOverlapAndInterior(simulator_.vanguard().grid(), elemMapper, overlapRows_, interiorRows_);
298 useWellConn_ = Parameters::Get<Parameters::MatrixAddWellContributions>();
299 const bool ownersFirst = Parameters::Get<Parameters::OwnerCellsFirst>();
301 const std::string msg =
"The linear solver no longer supports --owner-cells-first=false.";
305 OPM_THROW_NOLOG(std::runtime_error, msg);
308 const int interiorCellNum_ = detail::numMatrixRowsToUseInSolver(simulator_.vanguard().grid(),
true);
309 for (
auto& f : flexibleSolver_) {
310 f.interiorCellNum_ = interiorCellNum_;
315 const std::size_t size = simulator_.vanguard().grid().leafGridView().size(0);
316 detail::copyParValues(parallelInformation_, size, *comm_);
321 detail::printLinearSolverParameters(parameters_, activeSolverNum_, prm_, simulator_.gridView().comm());
323 element_chunks_ = std::make_unique<ElementChunksType>(simulator_.vanguard().gridView(), Dune::Partitions::all,
ThreadManager::maxThreads());
333 if (num > static_cast<int>(prm_.size()) - 1) {
334 OPM_THROW(std::logic_error,
"Solver number " + std::to_string(num) +
" not available.");
336 activeSolverNum_ = num;
337 if (simulator_.gridView().comm().rank() == 0) {
338 OpmLog::debug(
"Active solver = " + std::to_string(activeSolverNum_)
339 +
" (" + parameters_[activeSolverNum_].linsolver_ +
")");
345 return flexibleSolver_.size();
348 void initPrepare(
const Matrix& M, Vector& b)
350 const bool firstcall = (matrix_ ==
nullptr);
357 matrix_ =
const_cast<Matrix*
>(&M);
359 useWellConn_ = Parameters::Get<Parameters::MatrixAddWellContributions>();
363 if ( &M != matrix_ ) {
364 OPM_THROW(std::logic_error,
365 "Matrix objects are expected to be reused when reassembling!");
372 std::string type = prm_[activeSolverNum_].template get<std::string>(
"preconditioner.type",
"paroverilu0");
373 std::ranges::transform(type, type.begin(), ::tolower);
374 if (isParallel() && type !=
"paroverilu0") {
375 detail::makeOverlapRowsInvalid(getMatrix(), overlapRows_);
379 void prepare(
const SparseMatrixAdapter& M, Vector& b)
override 381 prepare(M.istlMatrix(), b);
384 void prepare(
const Matrix& M, Vector& b)
override 386 OPM_TIMEBLOCK(istlSolverPrepare);
390 prepareFlexibleSolver();
391 } OPM_CATCH_AND_RETHROW_AS_CRITICAL_ERROR(
"This is likely due to a faulty linear solver JSON specification. Check for errors related to missing nodes.");
395 void setResidual(Vector& )
override 400 void getResidual(Vector& b)
const override 405 void setMatrix(
const SparseMatrixAdapter& )
override 414 void resetSolveCount() {
418 bool solve(Vector& x)
override 420 OPM_TIMEBLOCK(istlSolverSolve);
423 const int verbosity = prm_[activeSolverNum_].get(
"verbosity", 0);
424 const bool write_matrix = verbosity > 10;
426 Helper::writeSystem(simulator_,
433 Dune::InverseOperatorResult result;
435 OPM_TIMEBLOCK(flexibleSolverApply);
436 assert(flexibleSolver_[activeSolverNum_].solver_);
437 flexibleSolver_[activeSolverNum_].solver_->apply(x, *rhs_, result);
440 iterations_ = result.iterations;
443 return checkConvergence(result);
459 const CommunicationType*
comm()
const override {
return comm_.get(); }
461 void setDomainIndex(
const int index)
463 domainIndex_ = index;
466 bool isNlddLocalSolver()
const 468 return parameters_[activeSolverNum_].is_nldd_local_solver_;
473 using Comm = Dune::OwnerOverlapCopyCommunication<int, int>;
476 bool checkConvergence(
const Dune::InverseOperatorResult& result)
const 481 bool isParallel()
const {
483 return !forceSerial_ && comm_->communicator().size() > 1;
489 void prepareFlexibleSolver()
491 OPM_TIMEBLOCK(flexibleSolverPrepare);
494 if (isNlddLocalSolver()) {
495 auto wellOp = std::make_unique<DomainWellModelAsLinearOperator<WellModel, Vector, Vector>>(simulator_.problem().wellModel());
496 wellOp->setDomainIndex(domainIndex_);
497 flexibleSolver_[activeSolverNum_].wellOperator_ = std::move(wellOp);
500 auto wellOp = std::make_unique<WellModelOperator>(simulator_.problem().wellModel());
501 flexibleSolver_[activeSolverNum_].wellOperator_ = std::move(wellOp);
504 std::function<Vector()> weightCalculator = this->getWeightsCalculator(prm_[activeSolverNum_], getMatrix(), pressureIndex);
505 OPM_TIMEBLOCK(flexibleSolverCreate);
506 flexibleSolver_[activeSolverNum_].create(getMatrix(),
508 prm_[activeSolverNum_],
516 OPM_TIMEBLOCK(flexibleSolverUpdate);
517 flexibleSolver_[activeSolverNum_].pre_->update();
528 if (flexibleSolver_.empty()) {
531 if (!flexibleSolver_[activeSolverNum_].solver_) {
535 if (flexibleSolver_[activeSolverNum_].pre_->hasPerfectUpdate()) {
541 if (this->parameters_[activeSolverNum_].cpr_reuse_setup_ == 0) {
545 if (this->parameters_[activeSolverNum_].cpr_reuse_setup_ == 1) {
547 return this->simulator_.problem().iterationContext().isFirstGlobalIteration();
549 if (this->parameters_[activeSolverNum_].cpr_reuse_setup_ == 2) {
553 if (this->parameters_[activeSolverNum_].cpr_reuse_setup_ == 3) {
557 if (this->parameters_[activeSolverNum_].cpr_reuse_setup_ == 4) {
559 const int step = this->parameters_[activeSolverNum_].cpr_reuse_interval_;
560 const bool create = ((solveCount_ % step) == 0);
564 const bool on_io_rank = (simulator_.gridView().comm().rank() == 0);
565 std::string msg =
"Invalid value: " + std::to_string(this->parameters_[activeSolverNum_].cpr_reuse_setup_)
566 +
" for --cpr-reuse-setup parameter, run with --help to see allowed values.";
570 throw std::runtime_error(msg);
579 std::function<Vector()> getWeightsCalculator(
const PropertyTree& prm,
580 const Matrix& matrix,
581 std::size_t pressIndex)
const 583 std::function<Vector()> weightsCalculator;
585 using namespace std::string_literals;
587 auto preconditionerType = prm.
get(
"preconditioner.type"s,
"cpr"s);
589 std::ranges::transform(preconditionerType, preconditionerType.begin(), ::tolower);
590 if (preconditionerType ==
"cpr" || preconditionerType ==
"cprt" 591 || preconditionerType ==
"cprw" || preconditionerType ==
"cprwt") {
592 const bool transpose = preconditionerType ==
"cprt" || preconditionerType ==
"cprwt";
593 const bool enableThreadParallel = this->parameters_[0].cpr_weights_thread_parallel_;
594 const auto weightsType = prm.
get(
"preconditioner.weight_type"s,
"quasiimpes"s);
595 if (weightsType ==
"quasiimpes") {
599 weightsCalculator = [matrix, transpose, pressIndex, enableThreadParallel]() {
600 return Amg::getQuasiImpesWeights<Matrix, Vector>(matrix,
603 enableThreadParallel);
605 }
else if ( weightsType ==
"trueimpes" ) {
607 [
this, pressIndex, enableThreadParallel]
609 Vector weights(rhs_->size());
610 ElementContext elemCtx(simulator_);
611 Amg::getTrueImpesWeights(pressIndex,
620 }
else if (weightsType ==
"trueimpesanalytic" ) {
622 [
this, pressIndex, enableThreadParallel]
624 Vector weights(rhs_->size());
625 ElementContext elemCtx(simulator_);
626 Amg::getTrueImpesWeightsAnalytic(pressIndex,
636 OPM_THROW(std::invalid_argument,
637 "Weights type " + weightsType +
638 "not implemented for cpr." 639 " Please use quasiimpes, trueimpes or trueimpesanalytic.");
642 return weightsCalculator;
651 const Matrix& getMatrix()
const 656 const Simulator& simulator_;
657 mutable int iterations_;
658 mutable int solveCount_;
659 std::any parallelInformation_;
665 int activeSolverNum_ = 0;
666 std::vector<detail::FlexibleSolverInfo<Matrix,Vector,CommunicationType>> flexibleSolver_;
667 std::vector<int> overlapRows_;
668 std::vector<int> interiorRows_;
670 int domainIndex_ = -1;
674 std::vector<FlowLinearSolverParameters> parameters_;
675 bool forceSerial_ =
false;
676 std::vector<PropertyTree> prm_;
678 std::shared_ptr< CommunicationType > comm_;
679 std::unique_ptr<ElementChunksType> element_chunks_;
684 #endif // OPM_ISTLSOLVER_HEADER_INCLUDED Simplifies multi-threaded capabilities.
Definition: threadmanager.hpp:35
const CommunicationType * comm() const override
Get the communication object used by the solver.
Definition: ISTLSolver.hpp:459
static bool checkConvergence(const Dune::InverseOperatorResult &result, const FlowLinearSolverParameters ¶meters)
Check the convergence of the linear solver.
Definition: AbstractISTLSolver.hpp:192
int numAvailableSolvers() const override
Get the number of available solvers.
Definition: ISTLSolver.hpp:343
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...))
Definition: propertysystem.hh:233
static unsigned maxThreads()
Return the maximum number of threads of the current process.
Definition: threadmanager.hpp:66
T get(const std::string &key) const
Retrieve property value given hierarchical property key.
Definition: PropertyTree.cpp:59
Helper class for grid instantiation of ECL file-format using problems.
This class solves the fully implicit black-oil system by solving the reduced system (after eliminatin...
Definition: FlowLinearSolverParameters.hpp:40
This file provides the infrastructure to retrieve run-time parameters.
Defines the common properties required by the porous medium multi-phase models.
const std::any & parallelInformation() const
Definition: ISTLSolver.hpp:457
bool shouldCreateSolver() const
Return true if we should (re)create the whole solver, instead of just calling update() on the precond...
Definition: ISTLSolver.hpp:524
Definition: matrixblock.hh:228
The class that allows to manipulate sparse matrices.
Definition: linalgproperties.hh:50
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
void eraseMatrix() override
Signals that the memory for the matrix internally in the solver could be erased.
Definition: ISTLSolver.hpp:327
Definition: FlowBaseProblemProperties.hpp:98
Declare the properties used by the infrastructure code of the finite volume discretizations.
void setActiveSolver(const int num) override
Set the active solver by its index.
Definition: ISTLSolver.hpp:331
A sparse matrix interface backend for BCRSMatrix from dune-istl.
int iterations() const override
Solve the system of linear equations Ax = b, with A being the combined derivative matrix of the resid...
Definition: ISTLSolver.hpp:454
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:33
void extractParallelGridInformationToISTL(const Dune::CpGrid &, std::any &)
Extracts the information about the data decomposition from the grid for dune-istl.
Definition: ExtractParallelGridInformationToISTL.cpp:46
ISTLSolver(const Simulator &simulator, const FlowLinearSolverParameters ¶meters, bool forceSerial=false)
Construct a system solver.
Definition: ISTLSolver.hpp:197
The Opm property system, traits with inheritance.
Definition: ISTLSolver.hpp:102
A sparse matrix interface backend for BCRSMatrix from dune-istl.
Definition: istlsparsematrixadapter.hh:42
This class carries all parameters for the NewtonIterationBlackoilInterleaved class.
Definition: FlowLinearSolverParameters.hpp:97
Definition: WellOperators.hpp:69
Abstract interface for ISTL solvers.
Definition: AbstractISTLSolver.hpp:44
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:83
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:38
Definition: blackoilmodel.hh:75
ISTLSolver(const Simulator &simulator)
Construct a system solver.
Definition: ISTLSolver.hpp:211
PropertyTree setupPropertyTree(FlowLinearSolverParameters p, bool linearSolverMaxIterSet, bool linearSolverReductionSet, bool tpsaSetup)
Set up a property tree intended for FlexibleSolver by either reading the tree from a JSON file or cre...
Definition: setupPropertyTree.cpp:182
int getSolveCount() const override
Get the count of how many times the solver has been called.
Definition: ISTLSolver.hpp:410
Definition: ISTLSolver.hpp:70