opm-simulators
ISTLSolverTPSA.hpp
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  Copyright 2025 NORCE AS
5 
6  This file is part of the Open Porous Media project (OPM).
7 
8  OPM is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 2 of the License, or
11  (at your option) any later version.
12 
13  OPM is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with OPM. If not, see <http://www.gnu.org/licenses/>.
20 
21  Consult the COPYING file in the top-level source directory of this
22  module for the precise wording of the license and the list of
23  copyright holders.
24 */
25 #ifndef ISTL_SOLVER_TPSA_HPP
26 #define ISTL_SOLVER_TPSA_HPP
27 
28 #include <dune/istl/owneroverlapcopy.hh>
29 
30 #include <opm/common/CriticalError.hpp>
31 #include <opm/common/ErrorMacros.hpp>
32 #include <opm/common/Exceptions.hpp>
33 
34 #include <opm/models/tpsa/tpsabaseproperties.hpp>
37 
38 #include <opm/simulators/linalg/AbstractISTLSolver.hpp>
39 #include <opm/simulators/linalg/ExtractParallelGridInformationToISTL.hpp>
40 #include <opm/simulators/linalg/ISTLSolver.hpp>
41 #include <opm/simulators/linalg/PropertyTree.hpp>
42 #include <opm/simulators/linalg/setupPropertyTree.hpp>
43 #include <opm/simulators/linalg/TPSALinearSolverParameters.hpp>
44 #include <opm/simulators/linalg/WriteSystemMatrixHelper.hpp>
45 
46 #include <algorithm>
47 #include <any>
48 #include <cctype>
49 #include <memory>
50 #include <stdexcept>
51 #include <string>
52 #include <utility>
53 #include <vector>
54 
55 #include <fmt/format.h>
56 
57 
58 namespace Opm {
59 
65 template <class TypeTag>
66 class ISTLSolverTPSA : public AbstractISTLSolver<GetPropType<TypeTag, Properties::SparseMatrixAdapterTPSA>,
67  GetPropType<TypeTag, Properties::GlobalEqVectorTPSA>>
68 {
73 
74  using Matrix = typename SparseMatrixAdapter::IstlMatrix;
75 
76 
77 #if HAVE_MPI
78  using CommunicationType = Dune::OwnerOverlapCopyCommunication<int,int>;
79 #else
80  using CommunicationType = Dune::Communication<int>;
81 #endif
82 
83 public:
89  ISTLSolverTPSA(const Simulator& simulator)
90  : simulator_(simulator)
91  , solveCount_(0)
92  , iterations_(0)
93  , matrix_(nullptr)
94  , rhs_(nullptr)
95  {
96  // Init parameters
97  parameters_.init();
98 
99  // Initialize linear solver
100  initialize();
101  }
102 
106  static void registerParameters()
107  {
109  }
110 
114  void initialize()
115  {
116  // Setup property tree for FlexibleSolver
117  prm_ = setupPropertyTree(parameters_, false, false, /*tpsaSetup=*/true);
118 
119  // Reset comm_ pointer
120 #if HAVE_MPI
121  comm_.reset( new CommunicationType( simulator_.vanguard().grid().comm() ) );
122 #endif
123 
124  // Extract and copy parallel grid information
125  extractParallelGridInformationToISTL(simulator_.vanguard().grid(), parallelInformation_);
126 #if HAVE_MPI
127  if (isParallel()) {
128  const std::size_t size = simulator_.vanguard().grid().leafGridView().size(0);
129  detail::copyParValues(parallelInformation_, size, *comm_);
130  }
131 #endif
132 
133  // Get info on overlapping rows
134  ElementMapper elemMapper(simulator_.vanguard().gridView(), Dune::mcmgElementLayout());
135  std::vector<int> dummyInteriorRows;
136  detail::findOverlapAndInterior(simulator_.vanguard().grid(), elemMapper, overlapRows_, dummyInteriorRows);
137 
138  // Set number of interior cells in FlexibleSolverInfo
139  flexibleSolver_.interiorCellNum_ = detail::numMatrixRowsToUseInSolver(simulator_.vanguard().grid(), true);
140 
141  // Print parameters to PRT/DBG logs.
142  detail::printLinearSolverParameters(parameters_, prm_, simulator_.gridView().comm());
143  }
144 
151  void initPrepare(const Matrix& M, Vector& b)
152  {
153  // Update matrix entries if it has not been initialized yet
154  const bool firstcall = (matrix_ == nullptr);
155  if (firstcall) {
156  // Model will not change the matrix object. Hence simply store a pointer to the original one with a deleter
157  // that does nothing.
158  // OBS: We need to be able to scale the linear system, hence const_cast
159  matrix_ = const_cast<Matrix*>(&M);
160  }
161  else {
162  // Pointers should not change; throw if the case
163  if (&M != matrix_) {
164  OPM_THROW(std::logic_error, "TPSA: Matrix objects are expected to be reused when reassembling!");
165  }
166 
167  }
168 
169  // Set right-hand side vector
170  rhs_ = &b;
171 
172  // Zero out the overlapping cells in matrix (not in ilu0 case)
173  std::string type = prm_.template get<std::string>("preconditioner.type", "paroverilu0");
174  std::transform(type.begin(), type.end(), type.begin(), ::tolower);
175  if (isParallel() && type != "paroverilu0") {
176  detail::makeOverlapRowsInvalid(getMatrix(), overlapRows_);
177  }
178  }
179 
183  void prepare(const Matrix& M, Vector& b) override
184  {
185  try {
186  initPrepare(M, b);
187 
189  }
190  OPM_CATCH_AND_RETHROW_AS_CRITICAL_ERROR
191  ("TPSA: Failure likely due to a faulty linear solver JSON specification. "
192  "Check for errors related to missing nodes.");
193  }
194 
198  void prepare(const SparseMatrixAdapter& M, Vector& b) override
199  {
200  prepare(M.istlMatrix(), b);
201  }
202 
210  {
211  // Create solver or just update preconditioner
212  if (!flexibleSolver_.solver_) {
213  // Dummy weights calculator
214  // TODO: TPSA specific weights calculation for AMG preconditioner
215  std::function<Vector()> weightCalculator;
216 
217  // Create FlexibleSolver
218  flexibleSolver_.create(getMatrix(),
219  isParallel(),
220  prm_,
221  /*pressureIndex=*/0,
222  weightCalculator,
223  /*forceSerial_=*/false,
224  comm_.get());
225  }
226  else {
227  // Update preconditioner
228  flexibleSolver_.pre_->update();
229  }
230  }
231 
235  bool solve(Vector& x) override
236  {
237  // Increase solver count
238  ++solveCount_;
239 
240  // Write system matrix if verbosity level is high
241  const int verbosity = prm_.get("verbosity", 0);
242  if (verbosity > 10) {
243  // simulator_ is only used to get names
244  Helper::writeSystem(simulator_,
245  getMatrix(),
246  *rhs_,
247  comm_.get());
248  }
249 
250  // Solve linear system
251  Dune::InverseOperatorResult result;
252  assert(flexibleSolver_.solver_);
253  flexibleSolver_.solver_->apply(x, *rhs_, result);
254 
255  // Store no. linear iterations
256  iterations_ = result.iterations;
257 
258  // Return result for convergence check (boolean)
259  return checkConvergence(result);
260  }
261 
266  {
267  solveCount_ = 0;
268  }
269 
270  // ////
271  // Unused AbstractISTLSolver functions
272  // ////
276  void eraseMatrix() override
277  { }
278 
282  void setActiveSolver(int /*num*/) override
283  { }
284 
288  int numAvailableSolvers() const override
289  {
290  return 1;
291  }
292 
296  void setResidual(Vector& /*b*/) override
297  { }
298 
302  void setMatrix(const SparseMatrixAdapter& /*M*/) override
303  { }
304 
305  // ///
306  // Public get functions
307  // ///
311  void getResidual(Vector& b) const override
312  {
313  b = *rhs_;
314  }
315 
319  int getSolveCount() const override
320  {
321  return solveCount_;
322  }
323 
327  int iterations() const override
328  {
329  return iterations_;
330  }
331 
335  const CommunicationType* comm() const override
336  {
337  return comm_.get();
338  }
339 
340 protected:
348  bool isParallel() const
349  {
350 #if HAVE_MPI
351  return comm_->communicator().size() > 1;
352 #else
353  return false;
354 #endif
355  }
356 
363  bool checkConvergence(const Dune::InverseOperatorResult& result) const
364  {
366  }
367 
368  // ///
369  // Protected get functions
370  // ///
376  Matrix& getMatrix()
377  {
378  if (!matrix_) {
379  OPM_THROW(std::runtime_error, "TPSA: System matrix \"M\" not defined!");
380  }
381  return *matrix_;
382  }
383 
389  const Matrix& getMatrix() const
390  {
391  if (!matrix_) {
392  OPM_THROW(std::runtime_error, "TPSA: System matrix \"M\" not defined!");
393  }
394  return *matrix_;
395  }
396 
397  const Simulator& simulator_;
398  std::any parallelInformation_;
399  int solveCount_;
400  int iterations_;
401 
403  TpsaLinearSolverParameters parameters_;
404  PropertyTree prm_;
405 
406  Matrix* matrix_;
407  Vector* rhs_;
408 
409  std::shared_ptr<CommunicationType> comm_;
410  std::vector<int> overlapRows_;
411 };
412 
413 } // namespace Opm
414 
415 #endif
ISTLSolverTPSA(const Simulator &simulator)
Constructor.
Definition: ISTLSolverTPSA.hpp:89
static void registerParameters()
Register runtime/default parameters for linear solver.
Definition: ISTLSolverTPSA.hpp:106
const Matrix & getMatrix() const
Get reference to system matrix object.
Definition: ISTLSolverTPSA.hpp:389
static bool checkConvergence(const Dune::InverseOperatorResult &result, const FlowLinearSolverParameters &parameters)
Check the convergence of the linear solver.
Definition: AbstractISTLSolver.hpp:192
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
T get(const std::string &key) const
Retrieve property value given hierarchical property key.
Definition: PropertyTree.cpp:59
void initialize()
Setup linear solver object based on runtime/default parameters.
Definition: ISTLSolverTPSA.hpp:114
Parametern for linear solver and preconditioner.
Definition: TPSALinearSolverParameters.hpp:55
void prepareFlexibleSolver()
Prepare linear solver.
Definition: ISTLSolverTPSA.hpp:209
void prepare(const SparseMatrixAdapter &M, Vector &b) override
Prepare the solver with the given matrix and right-hand side vector.
Definition: ISTLSolverTPSA.hpp:198
void resetSolveCount()
Reset number of solver calls to zero.
Definition: ISTLSolverTPSA.hpp:265
This file provides the infrastructure to retrieve run-time parameters.
void setActiveSolver(int) override
Set the active solver by its index.
Definition: ISTLSolverTPSA.hpp:282
const CommunicationType * comm() const override
Get the communication object used by the solver.
Definition: ISTLSolverTPSA.hpp:335
Class for setting up ISTL linear solvers for TPSA.
Definition: ISTLSolverTPSA.hpp:66
int getSolveCount() const override
Get the count of how many times the solver has been called.
Definition: ISTLSolverTPSA.hpp:319
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
void eraseMatrix() override
Signals that the memory for the matrix internally in the solver could be erased.
Definition: ISTLSolverTPSA.hpp:276
bool isParallel() const
Check for parallel session.
Definition: ISTLSolverTPSA.hpp:348
int iterations() const override
Get the number of iterations used in the last solve.
Definition: ISTLSolverTPSA.hpp:327
bool checkConvergence(const Dune::InverseOperatorResult &result) const
Check for linear solver convergence.
Definition: ISTLSolverTPSA.hpp:363
bool solve(Vector &x) override
Solve the system of equations Ax = b.
Definition: ISTLSolverTPSA.hpp:235
void extractParallelGridInformationToISTL(const Dune::CpGrid &, std::any &)
Extracts the information about the data decomposition from the grid for dune-istl.
Definition: ExtractParallelGridInformationToISTL.cpp:46
void prepare(const Matrix &M, Vector &b) override
Prepare the solver with the given matrix and right-hand side vector.
Definition: ISTLSolverTPSA.hpp:183
void initPrepare(const Matrix &M, Vector &b)
Prepare matix and rhs vector for linear solve.
Definition: ISTLSolverTPSA.hpp:151
void setMatrix(const SparseMatrixAdapter &) override
Set the matrix for the solver.
Definition: ISTLSolverTPSA.hpp:302
Matrix & getMatrix()
Get reference to system matrix object.
Definition: ISTLSolverTPSA.hpp:376
The Opm property system, traits with inheritance.
int numAvailableSolvers() const override
Get the number of available solvers.
Definition: ISTLSolverTPSA.hpp:288
Abstract interface for ISTL solvers.
Definition: AbstractISTLSolver.hpp:44
void getResidual(Vector &b) const override
Get the residual vector.
Definition: ISTLSolverTPSA.hpp:311
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:83
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:38
void setResidual(Vector &) override
Set the residual vector.
Definition: ISTLSolverTPSA.hpp:296
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
void init()
Internalize runtime parameters.
Definition: TPSALinearSolverParameters.cpp:37
static void registerParameters()
Register TPSA linear solver runtime parameters.
Definition: TPSALinearSolverParameters.cpp:59