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
49#endif
50
51#include <opm/grid/utility/SparseTable.hpp>
56
58
59namespace Opm {
60
73template <class TypeTag>
74class 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
109public:
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
119private:
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
146public:
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
ThermalGasWaterFlowProblem< Scalar, GpuView > make_view(ThermalGasWaterFlowProblem< Scalar, GpuBuffer > &buffer)
Definition: ThermalGasWaterFlowProblem.hpp:111
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
ThermalGasWaterFlowProblem< Scalar, GpuBuffer > copy_to_gpu(ThermalGasWaterFlowProblem< Scalar, Opm::VectorWithDefaultAllocator > &cpuProblem)
Definition: ThermalGasWaterFlowProblem.hpp:99
Definition: blackoilbioeffectsmodules.hh:45
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)