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  using ISTLSolver<TypeTag>::prepare;
188  void prepare(const Matrix& M, Vector& b) override
189  {
190  OPM_TIMEBLOCK(prepare);
191  [[maybe_unused]] const bool firstcall = (this->matrix_ == nullptr);
192 
193  // Avoid performing the decomposition on CPU when we also do it on GPU,
194  // but we do need to initialize the pointers.
195  if (gpuBridge_) {
196  ParentType::initPrepare(M,b);
197  } else {
198  ParentType::prepare(M,b);
199  }
200 
201 #if HAVE_OPENCL || HAVE_ROCSPARSE || HAVE_CUDA
202  // update matrix entries for solvers.
203  if (firstcall && gpuBridge_) {
204  // model will not change the matrix object. Hence simply store a pointer
205  // to the original one with a deleter that does nothing.
206  // Outch! We need to be able to scale the linear system! Hence const_cast
207  // setup sparsity pattern for jacobi matrix for preconditioner (only used for openclSolver)
208  gpuBridge_->numJacobiBlocks_ = Parameters::Get<Parameters::NumJacobiBlocks>();
209  gpuBridge_->prepare(this->simulator_.vanguard().grid(),
210  this->simulator_.vanguard().cartesianIndexMapper(),
211  this->simulator_.vanguard().schedule().getWellsatEnd(),
212  this->simulator_.vanguard().schedule().getPossibleFutureConnections(),
213  this->simulator_.vanguard().cellPartition(),
214  this->getMatrix().nonzeroes(), this->useWellConn_);
215  }
216 #endif
217  }
218 
219 
220  void setResidual(Vector& /* b */) override
221  {
222  // rhs_ = &b; // Must be handled in prepare() instead.
223  }
224 
225  void getResidual(Vector& b) const override
226  {
227  b = *(this->rhs_);
228  }
229 
230  void setMatrix(const SparseMatrixAdapter& /* M */) override
231  {
232  // matrix_ = &M.istlMatrix(); // Must be handled in prepare() instead.
233  }
234 
235  bool solve(Vector& x) override
236  {
237  if (!gpuBridge_) {
238  return ParentType::solve(x);
239  }
240 
241  OPM_TIMEBLOCK(istlSolverGpuBridgeSolve);
242  this->solveCount_ += 1;
243  // Write linear system if asked for.
244  const int verbosity = this->prm_[this->activeSolverNum_].template get<int>("verbosity", 0);
245  const bool write_matrix = verbosity > 10;
246  if (write_matrix) {
247  Helper::writeSystem(this->simulator_, //simulator is only used to get names
248  this->getMatrix(),
249  *(this->rhs_),
250  this->comm_.get());
251  }
252 
253  // Solve system.
254  Dune::InverseOperatorResult result;
255 
256  std::function<void(WellContributions<Scalar>&)> getContribs =
257  [this](WellContributions<Scalar>& w)
258  {
259  this->simulator_.problem().wellModel().getWellContributions(w);
260  };
261  if (!gpuBridge_->apply(*(this->rhs_), this->useWellConn_, getContribs,
262  this->simulator_.gridView().comm().rank(),
263  const_cast<Matrix&>(this->getMatrix()),
264  x, result))
265  {
266  if(gpuBridge_->gpuActive()){
267  // gpu solve fails use istl solver setup need to be done since it is not setup in prepare
268  ParentType::prepareFlexibleSolver();
269  }
270  assert(this->flexibleSolver_[this->activeSolverNum_].solver_);
271  this->flexibleSolver_[this->activeSolverNum_].solver_->apply(x, *(this->rhs_), result);
272  }
273 
274  // Check convergence, iterations etc.
275  return this->checkConvergence(result);
276  }
277 
278 protected:
279  std::unique_ptr<detail::GpuSolverInfo<Matrix, Vector>> gpuBridge_;
280 }; // end ISTLSolver
281 
282 } // namespace Opm
283 
284 #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
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
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:50
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:83