GpuVector.hpp
Go to the documentation of this file.
1/*
2 Copyright 2022-2023 SINTEF AS
3
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#ifndef OPM_GPUVECTOR_HEADER_HPP
20#define OPM_GPUVECTOR_HEADER_HPP
21
25
26#include <opm/common/ErrorMacros.hpp>
27
28#include <dune/common/fvector.hh>
29#include <dune/istl/bvector.hh>
30#include <fmt/format.h>
31
32#include <cstddef>
33#include <ostream>
34#include <stdexcept>
35#include <string>
36#include <vector>
37
38
39namespace Opm::gpuistl
40{
41
75template <typename T>
76class GpuVector
77{
78public:
79 using field_type = T;
80 using size_type = size_t;
81
82
91 GpuVector(const GpuVector<T>& other);
92
104 explicit GpuVector(const std::vector<T>& data);
105
114 GpuVector& operator=(const GpuVector<T>& other);
115
126 template<int BlockDimension>
127 explicit GpuVector(const Dune::BlockVector<Dune::FieldVector<T, BlockDimension>>& bvector)
128 : GpuVector(bvector.dim())
129 {
130 copyFromHost(bvector);
131 }
132
140 GpuVector& operator=(T scalar);
141
145 GpuVector() = default;
146
152 explicit GpuVector(const size_t numberOfElements);
153
154
164 GpuVector(const T* dataOnHost, const size_t numberOfElements);
165
169 virtual ~GpuVector() = default;
170
174 T* data();
175
179 const T* data() const;
180
188 template <int BlockDimension>
189 void copyFromHost(const Dune::BlockVector<Dune::FieldVector<T, BlockDimension>>& bvector)
190 {
191 m_buffer.copyFromHost(bvector);
192 }
193
202 template <int BlockDimension>
203 void copyFromHostAsync(const Dune::BlockVector<Dune::FieldVector<T, BlockDimension>>& bvector, cudaStream_t stream = detail::DEFAULT_STREAM)
204 {
205 // TODO: [perf] vector.dim() can be replaced by bvector.N() * BlockDimension
206 if (dim() != bvector.dim()) {
207 OPM_THROW(std::runtime_error,
208 fmt::format("Given incompatible vector size. GpuVector has size {}, \n"
209 "however, BlockVector has N() = {}, and dim = {}.",
210 dim(),
211 bvector.N(),
212 bvector.dim()));
213 }
214 const auto dataPointer = static_cast<const T*>(&(bvector[0][0]));
215 copyFromHostAsync(dataPointer, dim(), stream);
216 }
217
225 template <int BlockDimension>
226 void copyToHost(Dune::BlockVector<Dune::FieldVector<T, BlockDimension>>& bvector) const
227 {
228 m_buffer.copyToHost(bvector);
229 }
230
239 template <int BlockDimension>
240 void copyToHostAsync(Dune::BlockVector<Dune::FieldVector<T, BlockDimension>>& bvector, cudaStream_t stream = detail::DEFAULT_STREAM) const
241 {
242 // TODO: [perf] vector.dim() can be replaced by bvector.N() * BlockDimension
243 if (dim() != bvector.dim()) {
244 OPM_THROW(std::runtime_error,
245 fmt::format("Given incompatible vector size. GpuVector has size {},\n however, the BlockVector "
246 "has has N() = {}, and dim() = {}.",
247 dim(),
248 bvector.N(),
249 bvector.dim()));
250 }
251 const auto dataPointer = static_cast<T*>(&(bvector[0][0]));
252 copyToHostAsync(dataPointer, dim(), stream);
253 }
254
262 void copyFromHost(const T* dataPointer, size_t numberOfElements);
263
274 void copyFromHostAsync(const T* dataPointer, size_t numberOfElements, cudaStream_t stream = detail::DEFAULT_STREAM);
275
276
277
285 void copyToHost(T* dataPointer, size_t numberOfElements) const;
286
297 void copyToHostAsync(T* dataPointer, size_t numberOfElements, cudaStream_t stream = detail::DEFAULT_STREAM) const;
298
299
300
308 void copyFromHost(const std::vector<T>& data);
309
318 void copyFromHostAsync(const std::vector<T>& data, cudaStream_t stream = detail::DEFAULT_STREAM);
319
327 void copyToHost(std::vector<T>& data) const;
328
338 void copyToHostAsync(std::vector<T>& data, cudaStream_t stream = detail::DEFAULT_STREAM) const;
339
340
341
346 void copyFromDeviceToDevice(const GpuVector<T>& other);
347
348 void prepareSendBuf(GpuVector<T>& buffer, const GpuVector<int>& indexSet) const;
349 void syncFromRecvBuf(GpuVector<T>& buffer, const GpuVector<int>& indexSet);
350
359 GpuVector<T>& operator*=(const T& scalar);
360
369 GpuVector<T>& axpy(T alpha, const GpuVector<T>& y);
370
377 GpuVector<T>& operator+=(const GpuVector<T>& other);
378
385 GpuVector<T>& operator-=(const GpuVector<T>& other);
386
395 T dot(const GpuVector<T>& other) const;
396
404 T two_norm() const;
405
411 T dot(const GpuVector<T>& other, const GpuVector<int>& indexSet, GpuVector<T>& buffer) const;
412
418 T two_norm(const GpuVector<int>& indexSet, GpuVector<T>& buffer) const;
419
420
426 T dot(const GpuVector<T>& other, const GpuVector<int>& indexSet) const;
427
433 T two_norm(const GpuVector<int>& indexSet) const;
434
435
440 size_type dim() const;
441
450 void resize(size_t new_size);
451
456 std::vector<T> asStdVector() const;
457
462 template <int blockSize>
463 Dune::BlockVector<Dune::FieldVector<T, blockSize>> asDuneBlockVector() const
464 {
465 OPM_ERROR_IF(dim() % blockSize != 0,
466 fmt::format("blockSize is not a multiple of dim(). Given blockSize = {}, and dim() = {}",
467 blockSize,
468 dim()));
469
470 Dune::BlockVector<Dune::FieldVector<T, blockSize>> returnValue(dim() / blockSize);
471 copyToHost(returnValue);
472 return returnValue;
473 }
474
475
489 void setZeroAtIndexSet(const GpuVector<int>& indexSet);
490
491 // Slow method that creates a string representation of a GpuVector for debug purposes
492 std::string toDebugString()
493 {
494 std::vector<T> v = asStdVector();
495 std::string res = "";
496 for (T element : v){
497 res += std::to_string(element) + " ";
498 }
499 res += std::to_string(v[v.size()-1]);
500 return res;
501 }
502
503private:
504 GpuBuffer<T> m_buffer;
505 detail::CuBlasHandle& m_cuBlasHandle = detail::CuBlasHandle::getInstance();
506
507 void assertSameSize(const GpuVector<T>& other) const;
508 void assertSameSize(size_t size) const;
509
510 void assertHasElements() const;
511
515 static size_t checkedSize(size_t size);
516};
517
518} // namespace Opm::gpuistl
519
520// ADL bridge: convert GPU vector to Dune BlockVector and delegate to Dune's writer
521namespace Opm::gpuistl
522{
523template <typename T>
524inline void writeMatrixMarket(const GpuVector<T>& vectorOnDevice, std::ostream& ostr)
525{
526 const auto hostBlockVector = vectorOnDevice.template asDuneBlockVector<1>();
527 writeMatrixMarket(hostBlockVector, ostr);
528}
529} // namespace Opm::gpuistl
530#endif
static CuBlasHandle & getInstance()
getInstance creates (if necessary) and returns the single unique instance of CuBlasHandle (singleton)
static constexpr int dim
Definition: structuredgridvanguard.hh:68
void syncFromRecvBuf(T *deviceA, T *buffer, size_t numberOfElements, const int *indices)
constexpr cudaStream_t DEFAULT_STREAM
The default GPU stream (stream 0)
Definition: gpu_constants.hpp:31
void prepareSendBuf(const T *deviceA, T *buffer, size_t numberOfElements, const int *indices)
A small, fixed‑dimension MiniVector class backed by std::array that can be used in both host and CUDA...
Definition: GpuFlowProblem.hpp:48
std::string toDebugString()
Definition: GpuVector.hpp:492
void setZeroAtIndexSet(const GpuVector< int > &indexSet)
The GpuVector class is a simple (arithmetic) vector class for the GPU that wraps a GpuBuffer.
void writeMatrixMarket(const GpuVector< T > &vectorOnDevice, std::ostream &ostr)
Definition: GpuVector.hpp:524
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)