opm-simulators
tpfalinearizerstructs.hh
1 /*
2  Copyright 2026 Equinor ASA
3  This file is part of the Open Porous Media project (OPM).
4  OPM is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8  OPM is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  You should have received a copy of the GNU General Public License
13  along with OPM. If not, see <http://www.gnu.org/licenses/>.
14 */
15 
16 #ifndef TPFA_LINEARIZER_STRUCTS_HH
17 #define TPFA_LINEARIZER_STRUCTS_HH
18 
24 #include <cassert>
25 #include <vector>
26 
27 #include <opm/common/Exceptions.hpp>
28 #include <opm/grid/utility/SparseTable.hpp>
29 #include <opm/input/eclipse/Schedule/BCProp.hpp>
30 
31 #include <opm/common/utility/gpuistl_if_available.hpp>
32 #include <opm/common/utility/pointerArithmetic.hpp>
33 
34 namespace Opm {
35 
36 template <class Storage = std::vector<int>>
37 struct FullDomain
38 {
39  Storage cells;
40 };
41 
42 #if HAVE_CUDA && OPM_IS_COMPILING_WITH_GPU_COMPILER
43 inline FullDomain<gpuistl::GpuBuffer<int>> copy_to_gpu(FullDomain<> CPUDomain)
44 {
45  if (CPUDomain.cells.size() == 0) {
46  OPM_THROW(std::runtime_error, "Cannot copy empty full domain to GPU.");
47  }
48  return FullDomain<gpuistl::GpuBuffer<int>>{
49  gpuistl::GpuBuffer<int>(CPUDomain.cells)
50  };
51 };
52 
53 inline FullDomain<gpuistl::GpuView<int>> make_view(FullDomain<gpuistl::GpuBuffer<int>>& buffer)
54 {
55  if (buffer.cells.size() == 0) {
56  OPM_THROW(std::runtime_error, "Cannot make view of empty full domain buffer.");
57  }
58  return FullDomain<gpuistl::GpuView<int>>{
59  gpuistl::make_view(buffer.cells)
60  };
61 };
62 #endif
63 
64 template <class ResidualNBInfoType, class BlockType>
66 {
67  unsigned int neighbor;
68  ResidualNBInfoType res_nbinfo;
69  BlockType* matBlockAddress;
70 
71  template <class PtrType>
72  NeighborInfoStruct(unsigned int n, const ResidualNBInfoType& r, PtrType ptr)
73  : neighbor(n)
74  , res_nbinfo(r)
75  , matBlockAddress(static_cast<BlockType*>(ptr))
76  {
77  }
78 
79  // Add a default constructor
81  : neighbor(0)
82  , res_nbinfo()
83  , matBlockAddress(nullptr)
84  {
85  }
86 };
87 
88 template <class VectorBlock, class ScalarFluidState>
90  BCType type;
91  VectorBlock massRate;
92  unsigned pvtRegionIdx;
93  unsigned boundaryFaceIndex;
94  double faceArea;
95  double faceZCoord;
96  ScalarFluidState exFluidState;
97 };
98 
99 template <class BoundaryConditionData>
100 struct BoundaryInfo {
101  unsigned int cell;
102  int dir;
103  unsigned int bfIndex;
104  BoundaryConditionData bcdata;
105 };
106 
107 #if HAVE_CUDA && OPM_IS_COMPILING_WITH_GPU_COMPILER
108 namespace gpuistl {
109 
110  template <class MiniMatrixType,
111  class GpuMatrixType,
112  class CpuMatrixType,
113  class MatrixBlockType,
114  class ResidualNBInfoType>
116  cpuNeighborInfoTable,
117  GpuMatrixType& gpuJacobian,
118  CpuMatrixType& cpuJacobian)
119  {
120  // Convert the DUNE FieldVectors to MiniMatrix types
121  using StructWithMinimatrix = NeighborInfoStruct<ResidualNBInfoType, MiniMatrixType>;
122  using Scalar = typename GpuMatrixType::field_type;
123  std::vector<StructWithMinimatrix> minimatrices(cpuNeighborInfoTable.dataSize());
124  Scalar* gpuBufStart = gpuJacobian.getNonZeroValues().data();
125  Scalar* cpuBufStart = &(cpuJacobian[0][0][0][0]);
126 
127  // To compute the length of the buffer of the cpuJacobian we here assume we have a blocked
128  // BCRS matrix with square blocks and that the blocks are stored as Dune::FieldMatrix
129  using CpuBlockType = typename CpuMatrixType::block_type::BaseType;
130 
131  const size_t gpuBufferSize
132  = gpuJacobian.nonzeroes() * gpuJacobian.blockSize() * gpuJacobian.blockSize();
133  const size_t cpuBufferSize
134  = cpuJacobian.nonzeroes() * CpuBlockType::rows * CpuBlockType::cols;
135  assert(gpuBufferSize == cpuBufferSize);
136 
137  const auto& dataStorage = cpuNeighborInfoTable.dataStorage();
138  const size_t dataSize = cpuNeighborInfoTable.dataSize();
139 #ifdef _OPENMP
140 #pragma omp parallel for
141 #endif
142  for (size_t idx = 0; idx < dataSize; ++idx) {
143  const auto& e = dataStorage[idx];
144  Scalar* cpuPtr = &((*e.matBlockAddress)[0][0]);
145 
146  // convert the pointer from CPU to GPU pointer based on offset in CPU jacobian
147  Scalar* gpuPtr = ComputePtrBasedOnOffsetInOtherBuffer(
148  gpuBufStart, gpuBufferSize, cpuBufStart, cpuBufferSize, cpuPtr);
149 
150  minimatrices[idx] = StructWithMinimatrix(
151  e.neighbor, e.res_nbinfo, reinterpret_cast<MiniMatrixType*>(gpuPtr));
152  }
153 
154  return SparseTable<StructWithMinimatrix, gpuistl::GpuBuffer>(
155  gpuistl::GpuBuffer<StructWithMinimatrix>(minimatrices),
156  gpuistl::GpuBuffer<int>(cpuNeighborInfoTable.rowStarts())
157  );
158  }
159 
160  // Handle the BoundaryInfo structs
161  template <class GpuVecBlock,
162  class GpuFluidState,
163  class BoundaryInfoTypeGPU,
164  class BoundaryInfoTypeCPU,
165  typename GpuFluidSystemPtr>
166  auto copy_to_gpu(const std::vector<BoundaryInfoTypeCPU>& cpu_boundary_info,
167  const GpuFluidSystemPtr& dynamicGpuFluidSystemPtr)
168  {
169  std::vector<BoundaryInfoTypeGPU> gpu_boundary_info;
170  for (const auto& info : cpu_boundary_info) {
171  gpu_boundary_info.push_back(BoundaryInfoTypeGPU {
172  info.cell,
173  info.dir,
174  info.bfIndex,
175  BoundaryConditionData<GpuVecBlock, GpuFluidState> {
176  info.bcdata.type,
177  GpuVecBlock(info.bcdata.massRate),
178  info.bcdata.pvtRegionIdx,
179  info.bcdata.boundaryFaceIndex,
180  info.bcdata.faceArea,
181  info.bcdata.faceZCoord,
182  info.bcdata.exFluidState.withOtherFluidSystem(dynamicGpuFluidSystemPtr)}});
183  }
184 
185  return gpuistl::GpuBuffer<BoundaryInfoTypeGPU>(gpu_boundary_info);
186  }
187 
188  // Implemented for residual_, which is a vector of FieldVectors.
189  // We then make a GpuBuffer of MiniVectors.
190  template <class CPUResidualType, class GpuMiniVector>
191  auto copy_to_gpu_residual(CPUResidualType& residual)
192  {
193  std::vector<GpuMiniVector> vectorOfMiniVectors;
194  for (const auto& minivec : residual) {
195  vectorOfMiniVectors.emplace_back(minivec);
196  }
197 
198  return gpuistl::GpuBuffer<GpuMiniVector>(vectorOfMiniVectors);
199  }
200 
201 } // namespace gpuistl
202 #endif
203 
204 } // namespace Opm
205 
206 #endif // TPFA_LINEARIZER_STRUCTS_HH
Definition: BlackoilWellModel.hpp:90
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Definition: tpfalinearizerstructs.hh:89
Definition: tpfalinearizerstructs.hh:65
Definition: tpfalinearizerstructs.hh:37
Definition: tpfalinearizerstructs.hh:100