opm-simulators
tpfalinearizergpuparams.hh
Go to the documentation of this file.
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 
5  Copyright 2026 Equinor ASA
6 
7  This file is part of the Open Porous Media project (OPM).
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 */
30 #ifndef TPFA_LINEARIZER_GPU_PARAMS_HH
31 #define TPFA_LINEARIZER_GPU_PARAMS_HH
32 
33 #if HAVE_CUDA && OPM_IS_COMPILING_WITH_GPU_COMPILER
34 
35 #include <memory>
36 #include <string>
37 #include <vector>
38 
39 #include <opm/common/utility/gpuistl_if_available.hpp>
40 
41 #if USE_HIP
42 #include <opm/simulators/linalg/gpuistl_hip/GpuSparseMatrixWrapper.hpp>
43 #include <opm/simulators/linalg/gpuistl_hip/MiniMatrix.hpp>
44 #include <opm/simulators/linalg/gpuistl_hip/MiniVector.hpp>
45 #else
46 #include <opm/simulators/linalg/gpuistl/GpuSparseMatrixWrapper.hpp>
47 #include <opm/simulators/linalg/gpuistl/MiniMatrix.hpp>
48 #include <opm/simulators/linalg/gpuistl/MiniVector.hpp>
49 #endif
50 
51 #include <opm/grid/utility/SparseTable.hpp>
55 #include <opm/simulators/flow/ThermalGasWaterFlowProblem.hpp>
56 
57 #include <opm/models/discretization/common/tpfalinearizerstructs.hh>
58 
59 namespace Opm {
60 
73 template <class TypeTag>
74 class TpfaLinearizerGpuParams
75 {
76  using Scalar = GetPropType<TypeTag, Properties::Scalar>;
77  using GlobalEqVector = GetPropType<TypeTag, Properties::GlobalEqVector>;
78  using SparseMatrixAdapter = GetPropType<TypeTag, Properties::SparseMatrixAdapter>;
79  using LocalResidual = GetPropType<TypeTag, Properties::LocalResidual>;
80  using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
81  using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
82  using Model = GetPropType<TypeTag, Properties::Model>;
83  using Problem = GetPropType<TypeTag, Properties::Problem>;
84 
85  enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
86 
87  using MatrixBlockCPU = typename SparseMatrixAdapter::MatrixBlock;
88  using VectorBlockCPU = Dune::FieldVector<Scalar, numEq>;
89  using MatrixBlockGPU = gpuistl::MiniMatrix<Scalar, numEq>;
90  using VectorBlockGPU = gpuistl::MiniVector<Scalar, numEq>;
91 
92  using ResidualNBInfo = typename LocalResidual::ResidualNBInfo;
93  using NeighborInfoCPU = NeighborInfoStruct<ResidualNBInfo, MatrixBlockCPU>;
94  using NeighborInfoGPU = NeighborInfoStruct<ResidualNBInfo, MatrixBlockGPU>;
95 
96  using ScalarFluidState = typename IntensiveQuantities::ScalarFluidState;
97  using BoundaryConditionDataCPU = BoundaryConditionData<VectorBlockCPU, ScalarFluidState>;
98  using BoundaryInfoCPU = BoundaryInfo<BoundaryConditionDataCPU>;
99 
100  // Fluid system buffer/view/ptr types derived without spelling out the fluid-system
101  // template parameters explicitly.
102  using NonStaticFluidSystem = std::decay_t<decltype(FluidSystem::getNonStaticInstance())>;
103  using GpuFluidSystemBuffer = std::decay_t<decltype(::Opm::gpuistl::copy_to_gpu(
104  std::declval<NonStaticFluidSystem&>()))>;
105  using GpuFluidSystemView
106  = std::decay_t<decltype(::Opm::gpuistl::make_view(std::declval<GpuFluidSystemBuffer&>()))>;
107  using GpuFluidSystemPtr = std::shared_ptr<GpuFluidSystemView>;
108 
109 public:
110  // Type aliases required by callers to instantiate the GPU kernel templates.
111  using CorrectTypeTagView =
112  typename ::Opm::Properties::TTag::to_gpu_type_t<TypeTag, gpuistl::GpuView>;
113 
114  // GPUBOIQ and LocalResidualGPU are not taken from typetag as we need the
115  // outer class to template correctly here
116  using GPUBOIQ = BlackOilIntensiveQuantities<CorrectTypeTagView>;
117  using LocalResidualGPU = BlackOilLocalResidualTPFA<CorrectTypeTagView>;
118 
119 private:
120  using GpuScalarFluidState = typename GPUBOIQ::ScalarFluidState;
121  using BoundaryConditionDataGPU = BoundaryConditionData<VectorBlockGPU, GpuScalarFluidState>;
122  using BoundaryInfoGPU = BoundaryInfo<BoundaryConditionDataGPU>;
123 
124  using GpuModelBufferType = SimpleFIBlackOilModel<CorrectTypeTagView, gpuistl::GpuBuffer>;
125  using GpuFlowProblemBufferType = ThermalGasWaterFlowProblem<Scalar, gpuistl::GpuBuffer>;
126 
127  using GpuModel = GetPropType<TypeTag, Properties::GpuFIBlackOilModel>;
128 
129  FullDomain<gpuistl::GpuBuffer<int>> domainBuffer_;
130  SparseTable<NeighborInfoGPU, gpuistl::GpuBuffer> neighborInfoBuffer_;
131  // diagMatAddressView_ is non-owning: the underlying buffer lives in TpfaLinearizer.
132  gpuistl::GpuView<MatrixBlockGPU*> diagMatAddressView_;
133  gpuistl::GpuBuffer<VectorBlockGPU> residualBuffer_;
134  gpuistl::GpuView<VectorBlockGPU>
135  residualView_; // stored as lvalue because mutable ref must be provided
136  // dynamicGpuFluidSystemBuffer_ must be declared before dynamicGpuFluidSystemPtr_
137  // because the ptr holds a GpuView into the buffer's GPU memory.
138  GpuFluidSystemBuffer dynamicGpuFluidSystemBuffer_;
139  // The fluid-system ptr is kept alive because gpuModelBuffer_ and
140  // boundaryInfoBuffer_ store raw GPU pointers into it.
141  GpuFluidSystemPtr dynamicGpuFluidSystemPtr_;
142  GpuModelBufferType gpuModelBuffer_;
143  GpuFlowProblemBufferType gpuFlowProblemBuffer_;
144  gpuistl::GpuBuffer<BoundaryInfoGPU> boundaryInfoBuffer_;
145 
146 public:
167  TpfaLinearizerGpuParams(const FullDomain<>& domain,
168  const SparseTable<NeighborInfoCPU>& neighborInfo,
169  gpuistl::GpuSparseMatrixWrapper<Scalar>& gpuJacobian,
170  gpuistl::GpuBuffer<MatrixBlockGPU*>& gpuBufferDiagMatAddress,
171  typename SparseMatrixAdapter::IstlMatrix& cpuJacobian,
172  GlobalEqVector& residual,
173  const std::vector<BoundaryInfoCPU>& boundaryInfo,
174  Model& model,
175  const Problem& problem,
176  unsigned int numCells)
177  : domainBuffer_(copy_to_gpu(domain))
178  , neighborInfoBuffer_(
179  gpuistl::copy_to_gpu<MatrixBlockGPU>(neighborInfo, gpuJacobian, cpuJacobian))
180  , diagMatAddressView_(gpuistl::make_view(gpuBufferDiagMatAddress))
181  , residualBuffer_(gpuistl::copy_to_gpu_residual<GlobalEqVector, VectorBlockGPU>(residual))
182  , residualView_(gpuistl::make_view(residualBuffer_))
183  , dynamicGpuFluidSystemBuffer_(
184  ::Opm::gpuistl::copy_to_gpu(FluidSystem::getNonStaticInstance()))
185  , dynamicGpuFluidSystemPtr_(
186  gpuistl::make_gpu_shared_ptr(::Opm::gpuistl::make_view(dynamicGpuFluidSystemBuffer_)))
187  , gpuModelBuffer_([&]() -> GpuModelBufferType {
188  std::vector<Scalar> volumes(numCells);
189  for (unsigned i = 0; i < numCells; ++i) {
190  volumes[domain.cells[i]] = model.dofTotalVolume(domain.cells[i]);
191  }
192  GpuModel gpuModel(
193  model.intensiveQuantityCache()[0], model.intensiveQuantityCache()[1], volumes);
194  return gpuistl::copy_to_gpu(gpuModel, *dynamicGpuFluidSystemPtr_.get());
195  }())
196  , gpuFlowProblemBuffer_([&]() -> GpuFlowProblemBufferType {
197  std::vector<Scalar> alpha0(numCells);
198  std::vector<Scalar> alpha1(numCells);
199  std::vector<Scalar> alpha2(numCells);
200  const auto& thermalHalfTransBoundary
201  = problem.eclTransmissibilities().getThermalHalfTransBoundary();
202  for (const auto& [key, value] : thermalHalfTransBoundary) {
203  const unsigned cell = key.first;
204  const unsigned dir = key.second;
205  if (dir == 0) {
206  alpha0[cell] = value;
207  } else if (dir == 1) {
208  alpha1[cell] = value;
209  } else if (dir == 2) {
210  alpha2[cell] = value;
211  } else {
212  OPM_THROW(std::logic_error,
213  "Invalid direction for thermal half transmissibility: "
214  + std::to_string(dir));
215  }
216  }
217  ThermalGasWaterFlowProblem<Scalar> gpuFlowProblem(
218  alpha0, alpha1, alpha2, problem.moduleParams());
219  return gpuistl::copy_to_gpu(gpuFlowProblem);
220  }())
221  , boundaryInfoBuffer_(
222  gpuistl::copy_to_gpu<VectorBlockGPU, GpuScalarFluidState, BoundaryInfoGPU>(
223  boundaryInfo, *dynamicGpuFluidSystemPtr_.get()))
224  {
225  }
226 
227  auto domainView()
228  {
229  return make_view(domainBuffer_);
230  }
231 
232  auto neighborInfoView()
233  {
234  return gpuistl::make_view(neighborInfoBuffer_);
235  }
236 
237  auto& diagMatAddressView()
238  {
239  return diagMatAddressView_;
240  }
241 
242  auto& residualView()
243  {
244  return residualView_;
245  }
246 
247  auto modelView()
248  {
249  return gpuistl::make_view(gpuModelBuffer_);
250  }
251 
252  auto flowProblemView()
253  {
254  return gpuistl::make_view(gpuFlowProblemBuffer_);
255  }
256 
257  auto boundaryInfoView()
258  {
259  return gpuistl::make_view(boundaryInfoBuffer_);
260  }
261 
262  std::size_t boundaryInfoSize() const
263  {
264  return boundaryInfoBuffer_.size();
265  }
266 
273  void copyResidualToHost(GlobalEqVector& residual, unsigned numCells)
274  {
275  auto cpuResidualFromGpu = residualBuffer_.asStdVector();
276  std::memcpy(residual.data(), cpuResidualFromGpu.data(), numCells * numEq * sizeof(Scalar));
277  }
278 
284  void copyJacobianToHost(SparseMatrixAdapter& jacobian,
285  gpuistl::GpuSparseMatrixWrapper<Scalar>& gpuJacobian)
286  {
287  auto gpuJacobianNonZeroes = gpuJacobian.getNonZeroValues().asStdVector();
288  auto& cpuJacobian = jacobian.istlMatrix();
289  const std::size_t totalMatrixSize = cpuJacobian.nonzeroes() * numEq * numEq;
290  std::memcpy(&(cpuJacobian[0][0][0][0]),
291  gpuJacobianNonZeroes.data(),
292  totalMatrixSize * sizeof(Scalar));
293  }
294 };
295 
296 } // namespace Opm
297 
298 #endif // HAVE_CUDA && OPM_IS_COMPILING_WITH_GPU_COMPILER
299 
300 #endif // TPFA_LINEARIZER_GPU_PARAMS_HH
Contains the quantities which are are constant within a finite volume in the black-oil model...
Calculates the local residual of the black oil model.
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
std::shared_ptr< T > make_gpu_shared_ptr()
Creates a shared pointer managing GPU-allocated memory of the specified element type.
Definition: gpu_smart_pointer.hpp:48