opm-simulators
ISTLSolverGpuBridge.hpp
1 /*
2  Copyright 2016 IRIS AS
3  Copyright 2019, 2020 Equinor ASA
4  Copyright 2020 SINTEF Digital, Mathematics and Cybernetics
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 3 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 
22 #ifndef OPM_ISTLSOLVER_WITH_GPUBRIDGE_HEADER_INCLUDED
23 #define OPM_ISTLSOLVER_WITH_GPUBRIDGE_HEADER_INCLUDED
24 
25 #include <opm/simulators/linalg/ISTLSolver.hpp>
26 
27 #include <cstddef>
28 #include <memory>
29 #include <set>
30 #include <string>
31 #include <vector>
32 
33 namespace Opm {
34 
35 class Well;
36 
37 template<class Matrix, class Vector, int block_size> class GpuBridge;
38 template<class Scalar> class WellContributions;
39 namespace detail {
40 
41 template<class Matrix, class Vector>
43 {
44  using Scalar = typename Vector::field_type;
45  using WellContribFunc = std::function<void(WellContributions<Scalar>&)>;
47 
48  GpuSolverInfo(const std::string& accelerator_mode,
49  const int linear_solver_verbosity,
50  const int maxit,
51  const Scalar tolerance,
52  const int platformID,
53  const int deviceID,
54  const bool opencl_ilu_parallel,
55  const std::string& linsolver);
56 
57  ~GpuSolverInfo();
58 
59  template<class Grid>
60  void prepare(const Grid& grid,
61  const Dune::CartesianIndexMapper<Grid>& cartMapper,
62  const std::vector<Well>& wellsForConn,
63  const std::unordered_map<std::string, std::set<int>>& possibleFutureConnections,
64  const std::vector<int>& cellPartition,
65  const std::size_t nonzeroes,
66  const bool useWellConn);
67 
68  bool apply(Vector& rhs,
69  const bool useWellConn,
70  WellContribFunc getContribs,
71  const int rank,
72  Matrix& matrix,
73  Vector& x,
74  Dune::InverseOperatorResult& result);
75 
76  bool gpuActive();
77 
78  int numJacobiBlocks_ = 0;
79 
80 private:
83  template<class Grid>
84  void blockJacobiAdjacency(const Grid& grid,
85  const std::vector<int>& cell_part,
86  std::size_t nonzeroes);
87 
88  void copyMatToBlockJac(const Matrix& mat, Matrix& blockJac);
89 
90  std::unique_ptr<Bridge> bridge_;
91  std::string accelerator_mode_;
92  std::unique_ptr<Matrix> blockJacobiForGPUILU0_;
93  std::vector<std::set<int>> wellConnectionsGraph_;
94 };
95 
96 }
97 
102 template <class TypeTag>
103 class ISTLSolverGpuBridge : public ISTLSolver<TypeTag>
104 {
105 protected:
106  using ParentType = ISTLSolver<TypeTag>;
109  using SparseMatrixAdapter = GetPropType<TypeTag, Properties::SparseMatrixAdapter>;
114  using Matrix = typename SparseMatrixAdapter::IstlMatrix;
117  using AbstractSolverType = Dune::InverseOperator<Vector, Vector>;
118  using AbstractOperatorType = Dune::AssembledLinearOperator<Matrix, Vector, Vector>;
119  using AbstractPreconditionerType = Dune::PreconditionerWithUpdate<Vector, Vector>;
122  constexpr static std::size_t pressureIndex = GetPropType<TypeTag, Properties::Indices>::pressureSwitchIdx;
123 
124 #if HAVE_MPI
125  using CommunicationType = Dune::OwnerOverlapCopyCommunication<int,int>;
126 #else
127  using CommunicationType = Dune::Communication<int>;
128 #endif
129 
130 public:
131  using AssembledLinearOperatorType = Dune::AssembledLinearOperator< Matrix, Vector, Vector >;
132 
137  ISTLSolverGpuBridge(const Simulator& simulator, const FlowLinearSolverParameters& parameters)
138  : ParentType(simulator, parameters)
139  {
140  initializeGpu();
141  }
142 
145  explicit ISTLSolverGpuBridge(const Simulator& simulator)
146  : ParentType(simulator)
147  {
148  initializeGpu();
149  }
150 
151  void initializeGpu()
152  {
153  OPM_TIMEBLOCK(initializeGpu);
154 
155  std::string accelerator_mode = Parameters::Get<Parameters::AcceleratorMode>();
156  // Force accelerator mode to none if using MPI.
157  if ((this->simulator_.vanguard().grid().comm().size() > 1) && (accelerator_mode != "none")) {
158  const bool on_io_rank = (this->simulator_.gridView().comm().rank() == 0);
159  if (on_io_rank) {
160  OpmLog::warning("Cannot use AcceleratorMode feature with MPI, setting AcceleratorMode to 'none'.");
161  }
162  accelerator_mode = "none";
163  }
164 
165  if (accelerator_mode == "none") {
166  return;
167  }
168 
169  // Initialize the GpuBridge
170  const int platformID = Parameters::Get<Parameters::OpenclPlatformId>();
171  const int deviceID = Parameters::Get<Parameters::GpuDeviceId>();
172  const int maxit = Parameters::Get<Parameters::LinearSolverMaxIter>();
173  const double tolerance = Parameters::Get<Parameters::LinearSolverReduction>();
174  const bool opencl_ilu_parallel = Parameters::Get<Parameters::OpenclIluParallel>();
175  const int linear_solver_verbosity = this->parameters_[0].linear_solver_verbosity_;
176  std::string linsolver = Parameters::Get<Parameters::LinearSolver>();
177  gpuBridge_ = std::make_unique<detail::GpuSolverInfo<Matrix,Vector>>(accelerator_mode,
178  linear_solver_verbosity,
179  maxit,
180  tolerance,
181  platformID,
182  deviceID,
183  opencl_ilu_parallel,
184  linsolver);
185  }
186 
187  void prepare(const Matrix& M, Vector& b)
188  {
189  OPM_TIMEBLOCK(prepare);
190  [[maybe_unused]] const bool firstcall = (this->matrix_ == nullptr);
191 
192  // Avoid performing the decomposition on CPU when we also do it on GPU,
193  // but we do need to initialize the pointers.
194  if (gpuBridge_) {
195  ParentType::initPrepare(M,b);
196  } else {
197  ParentType::prepare(M,b);
198  }
199 
200 #if HAVE_OPENCL || HAVE_ROCSPARSE || HAVE_CUDA
201  // update matrix entries for solvers.
202  if (firstcall && gpuBridge_) {
203  // model will not change the matrix object. Hence simply store a pointer
204  // to the original one with a deleter that does nothing.
205  // Outch! We need to be able to scale the linear system! Hence const_cast
206  // setup sparsity pattern for jacobi matrix for preconditioner (only used for openclSolver)
207  gpuBridge_->numJacobiBlocks_ = Parameters::Get<Parameters::NumJacobiBlocks>();
208  gpuBridge_->prepare(this->simulator_.vanguard().grid(),
209  this->simulator_.vanguard().cartesianIndexMapper(),
210  this->simulator_.vanguard().schedule().getWellsatEnd(),
211  this->simulator_.vanguard().schedule().getPossibleFutureConnections(),
212  this->simulator_.vanguard().cellPartition(),
213  this->getMatrix().nonzeroes(), this->useWellConn_);
214  }
215 #endif
216  }
217 
218 
219  void setResidual(Vector& /* b */)
220  {
221  // rhs_ = &b; // Must be handled in prepare() instead.
222  }
223 
224  void getResidual(Vector& b) const
225  {
226  b = *(this->rhs_);
227  }
228 
229  void setMatrix(const SparseMatrixAdapter& /* M */)
230  {
231  // matrix_ = &M.istlMatrix(); // Must be handled in prepare() instead.
232  }
233 
234  bool solve(Vector& x)
235  {
236  if (!gpuBridge_) {
237  return ParentType::solve(x);
238  }
239 
240  OPM_TIMEBLOCK(istlSolverGpuBridgeSolve);
241  this->solveCount_ += 1;
242  // Write linear system if asked for.
243  const int verbosity = this->prm_[this->activeSolverNum_].template get<int>("verbosity", 0);
244  const bool write_matrix = verbosity > 10;
245  if (write_matrix) {
246  Helper::writeSystem(this->simulator_, //simulator is only used to get names
247  this->getMatrix(),
248  *(this->rhs_),
249  this->comm_.get());
250  }
251 
252  // Solve system.
253  Dune::InverseOperatorResult result;
254 
255  std::function<void(WellContributions<Scalar>&)> getContribs =
256  [this](WellContributions<Scalar>& w)
257  {
258  this->simulator_.problem().wellModel().getWellContributions(w);
259  };
260  if (!gpuBridge_->apply(*(this->rhs_), this->useWellConn_, getContribs,
261  this->simulator_.gridView().comm().rank(),
262  const_cast<Matrix&>(this->getMatrix()),
263  x, result))
264  {
265  if(gpuBridge_->gpuActive()){
266  // gpu solve fails use istl solver setup need to be done since it is not setup in prepare
267  ParentType::prepareFlexibleSolver();
268  }
269  assert(this->flexibleSolver_[this->activeSolverNum_].solver_);
270  this->flexibleSolver_[this->activeSolverNum_].solver_->apply(x, *(this->rhs_), result);
271  }
272 
273  // Check convergence, iterations etc.
274  return this->checkConvergence(result);
275  }
276 
277 protected:
278  std::unique_ptr<detail::GpuSolverInfo<Matrix, Vector>> gpuBridge_;
279 }; // end ISTLSolver
280 
281 } // namespace Opm
282 
283 #endif // OPM_ISTLSOLVER_WITH_GPUBRIDGE_HEADER_INCLUDED
Simplifies multi-threaded capabilities.
Definition: threadmanager.hpp:35
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
ISTLSolverGpuBridge(const Simulator &simulator, const FlowLinearSolverParameters &parameters)
Construct a system solver.
Definition: ISTLSolverGpuBridge.hpp:137
This class solves the fully implicit black-oil system by solving the reduced system (after eliminatin...
Definition: FlowLinearSolverParameters.hpp:40
ISTLSolverGpuBridge(const Simulator &simulator)
Construct a system solver.
Definition: ISTLSolverGpuBridge.hpp:145
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Definition: ISTLSolverGpuBridge.hpp:42
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:33
This class carries all parameters for the NewtonIterationBlackoilInterleaved class.
Definition: FlowLinearSolverParameters.hpp:97
GpuBridge acts as interface between opm-simulators with the GpuSolvers.
Definition: GpuBridge.hpp:36
This class solves the fully implicit black-oil system by solving the reduced system (after eliminatin...
Definition: FlowLinearSolverParameters.hpp:37
Definition: WellOperators.hpp:69
Definition: CollectDataOnIORank.hpp:49
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:83