SparseTable.hpp
Go to the documentation of this file.
1//===========================================================================
2//
3// File: SparseTable.hpp
4//
5// Created: Fri Apr 24 09:50:27 2009
6//
7// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
8//
9// $Date$
10//
11// $Revision$
12//
13//===========================================================================
14
15/*
16 Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
17 Copyright 2009, 2010 Statoil ASA.
18
19 This file is part of the Open Porous Media project (OPM).
20
21 OPM is free software: you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation, either version 3 of the License, or
24 (at your option) any later version.
25
26 OPM is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with OPM. If not, see <http://www.gnu.org/licenses/>.
33*/
34
35#ifndef OPM_SPARSETABLE_HEADER
36#define OPM_SPARSETABLE_HEADER
37
40
41#if HAVE_OPM_COMMON
42#include <opm/common/utility/gpuistl_if_available.hpp>
43#endif
44
45#include <algorithm>
46#include <cassert>
47#include <numeric>
48#include <ostream>
49#include <type_traits>
50#include <vector>
51
52namespace Opm
53{
54
55
56 template<class>
57inline constexpr bool always_false_v = false;
58
59// Poison iterator is a helper class that will allow for compilation only when it is not used.
60// Its intention is to be used so that we can have a SparseTable of GPU data, which requires the
61// GPUBuffer intermediate storage type, which does not support iterators.
62template<class T>
64 // iterator traits so it type-checks where an iterator is required
65 using iterator_category = std::input_iterator_tag;
66 using value_type = T;
67 using difference_type = std::ptrdiff_t;
68 using pointer = T*;
69 using reference = T&;
70
71 PoisonIterator() = default;
72
73 // Dereference
75 static_assert(always_false_v<T>, "PoisonIterator: operator*() is not allowed.");
76 return *ptr_;
77 }
78
80 static_assert(always_false_v<T>, "PoisonIterator: operator->() is not allowed.");
81 return ptr_;
82 }
83
84 // Pre-increment
86 static_assert(always_false_v<T>, "PoisonIterator: operator++() is not allowed.");
87 return *this;
88 }
89
90 // Post-increment
92 static_assert(always_false_v<T>, "PoisonIterator: operator++(int) is not allowed.");
93 return *this;
94 }
95
96 // Equality/inequality
97 friend bool operator==(const PoisonIterator&, const PoisonIterator&) {
98 static_assert(always_false_v<T>, "PoisonIterator: operator== is not allowed.");
99 return true;
100 }
101
102 friend bool operator!=(const PoisonIterator&, const PoisonIterator&) {
103 static_assert(always_false_v<T>, "PoisonIterator: operator!= is not allowed.");
104 return false;
105 }
106
107private:
108 T* ptr_ = nullptr; // placeholder to keep types consistent
109};
110
115 template <typename T, template <typename, typename...> class Storage = std::vector>
117 {
118 public:
121 : row_start_(1, 0)
122 {
123 }
124
130 template <typename DataIter, typename IntegerIter>
131 SparseTable(DataIter data_beg, DataIter data_end,
132 IntegerIter rowsize_beg, IntegerIter rowsize_end)
133 : data_(data_beg, data_end)
134 {
135 setRowStartsFromSizes(rowsize_beg, rowsize_end);
136 }
137
138 SparseTable (Storage<T>&& data, Storage<int>&& row_starts)
139 : data_(std::move(data))
140 , row_start_(std::move(row_starts))
141 {
142 // removed for non-default template instantiations
143 // because we cannot access the zero'th element if Storage is a GpuBuffer
144 if constexpr (std::is_same_v<Storage<T>, std::vector<T>>) {
145 OPM_ERROR_IF(row_start_.size() == 0 || row_start_[0] != 0,
146 "Invalid row_start array");
147 }
148 }
149
150
157 template <typename DataIter, typename IntegerIter>
158 void assign(DataIter data_beg, DataIter data_end,
159 IntegerIter rowsize_beg, IntegerIter rowsize_end)
160 {
161 data_.assign(data_beg, data_end);
162 setRowStartsFromSizes(rowsize_beg, rowsize_end);
163 }
164
165
169 template <typename IntegerIter>
170 void allocate(IntegerIter rowsize_beg, IntegerIter rowsize_end)
172 typedef typename Storage<T>::size_type sz_t;
174 sz_t ndata = std::accumulate(rowsize_beg, rowsize_end, sz_t(0));
175 data_.resize(ndata);
176 setRowStartsFromSizes(rowsize_beg, rowsize_end);
177 }
178
179
181 template <typename DataIter>
182 void appendRow(DataIter row_beg, DataIter row_end)
183 {
184 data_.insert(data_.end(), row_beg, row_end);
185 row_start_.push_back(data_.size());
186 }
187
190 {
191 return row_start_.size()==1;
192 }
193
196 {
197 return row_start_.size() - 1;
198 }
199
201 void reserve(int exptd_nrows, int exptd_ndata)
202 {
203 row_start_.reserve(exptd_nrows + 1);
204 data_.reserve(exptd_ndata);
205 }
206
208 void swap(SparseTable<T>& other)
209 {
210 row_start_.swap(other.row_start_);
211 data_.swap(other.data_);
212 }
213
216 {
217 return data_.size();
218 }
219
221 OPM_HOST_DEVICE int rowSize(int row) const
222 {
223#ifndef NDEBUG
224 OPM_ERROR_IF(row < 0 || row >= size(),
225 "Row index " + std::to_string(row) + " is out of range");
226#endif
227 return row_start_[row + 1] - row_start_[row];
228 }
229
231 void clear()
232 {
233 data_.clear();
234 row_start_.resize(1);
235 }
236
237 // Helper templates to select iterator range types only if (const_)iterator exists.
238 // Default: PoisonIterator (for non-traversable types)
239 template<class U, class = void>
243 };
244
245 // If Storage has const_iterator, use it (e.g. std::vector)
246 template<class U>
247 struct row_type_helper<U, std::void_t<typename U::const_iterator>> {
250 };
251
252#if HAVE_CUDA
253 // Specialization for GpuView: use its iterator
254 template<typename TT>
255 struct row_type_helper<gpuistl::GpuView<TT>> {
258 };
259
260 // Specialization for GpuBuffer: always PoisonIterator
261 template<typename TT>
262 struct row_type_helper<gpuistl::GpuBuffer<TT>> {
265 };
266#endif // HAVE_CUDA
267
268 using row_type = typename row_type_helper<Storage<T>>::const_type;
269 using mutable_row_type = typename row_type_helper<Storage<T>>::mutable_type;
270
273 {
274 assert(row >= 0 && row < size());
275 return row_type{data_.begin()+ row_start_[row],
276 data_.begin() + row_start_[row + 1]};
277 }
278
281 {
282 assert(row >= 0 && row < size());
283 return mutable_row_type{data_.begin() + row_start_[row],
284 data_.begin() + row_start_[row + 1]};
285 }
286
290 {
291 public:
292 OPM_HOST_DEVICE Iterator(const SparseTable& table, const int begin_row_index)
293 : table_(table)
294 , row_index_(begin_row_index)
295 {
296 }
298 {
299 ++row_index_;
300 return *this;
301 }
303 {
304 return table_[row_index_];
305 }
307 {
308 assert(&table_ == &other.table_);
309 return row_index_ == other.row_index_;
310 }
312 {
313 return !(*this == other);
314 }
315 private:
316 const SparseTable& table_;
317 int row_index_;
318 };
319
322 {
323 return Iterator(*this, 0);
324 }
326 {
327 return Iterator(*this, size());
328 }
329
331 OPM_HOST_DEVICE bool operator==(const SparseTable& other) const
332 {
333 return data_ == other.data_ && row_start_ == other.row_start_;
334 }
335
336 template<class charT, class traits>
337 void print(std::basic_ostream<charT, traits>& os) const
338 {
339 os << "Number of rows: " << size() << '\n';
340
341 os << "Row starts = [";
342 std::ranges::copy(row_start_, std::ostream_iterator<int>(os, " "));
343 os << "\b]\n";
344
345 os << "Data values = [";
346 std::ranges::copy(data_, std::ostream_iterator<T>(os, " "));
347 os << "\b]\n";
348 }
349 const T data(int i)const {
350 return data_[i];
351 }
352
353 // Get pointer to start of databuffer
354 // This is useful for getting access to the buffer itself so we can copy to GPU easily
355 const T* dataPtr() const
356 {
357 return data_.data();
358 }
359
360 // Access the data being stored directly (for instance used for copying to GPU)
361 const Storage<T>& dataStorage() const
362 {
363 return data_;
364 }
365
366 // Access indices of where all rows start
367 const Storage<int>& rowStarts() const
368 {
369 return row_start_;
370 }
371 private:
372 Storage<T> data_;
373 // Like in the compressed row sparse matrix format,
374 // row_start_.size() is equal to the number of rows + 1.
375 Storage<int> row_start_;
376
377 template <class IntegerIter>
378 void setRowStartsFromSizes(IntegerIter rowsize_beg, IntegerIter rowsize_end)
379 {
380#ifndef NDEBUG
381 // Check that all row sizes given are nonnegative.
382 for (auto it = rowsize_beg; it != rowsize_end; ++it) {
383 if (*it < 0) {
384 OPM_THROW(std::runtime_error, "Negative row size given.");
385 }
386 }
387#endif
388 // Since we do not store the row sizes, but cumulative row sizes,
389 // we have to create the cumulative ones.
390 int num_rows = rowsize_end - rowsize_beg;
391 row_start_.resize(num_rows + 1);
392 row_start_[0] = 0;
393 std::partial_sum(rowsize_beg, rowsize_end, row_start_.begin() + 1);
394 // Check that data_ and row_start_ match.
395 if (int(data_.size()) != row_start_.back()) {
396 OPM_THROW(std::runtime_error, "End of row start indices different from data size.");
397 }
398
399 }
400 };
401
402} // namespace Opm
403
404#if HAVE_CUDA
405namespace Opm::gpuistl {
406
407template <class T>
408auto copy_to_gpu(const SparseTable<T>& cpu_table)
409{
410 return SparseTable<T, GpuBuffer>(
411 GpuBuffer<T>(cpu_table.dataStorage()),
412 GpuBuffer<int>(cpu_table.rowStarts())
413 );
414}
415
416template <class T>
417auto make_view(SparseTable<T, GpuBuffer>& buffer_table)
418{
419 return SparseTable<T, GpuView>(
420 GpuView<T>(const_cast<T*>(buffer_table.dataStorage().data()),
421 buffer_table.dataStorage().size()),
422 GpuView<int>(const_cast<int*>(buffer_table.rowStarts().data()),
423 buffer_table.rowStarts().size())
424 );
425}
426
427} // namespace Opm::gpuistl
428#endif // HAVE_CUDA
429
430#endif // OPM_SPARSETABLE_HEADER
#define OPM_THROW(Exception, message)
Definition: ErrorMacros.hpp:29
#define OPM_ERROR_IF(condition, message)
Definition: ErrorMacros.hpp:40
#define OPM_HOST_DEVICE
Definition: IteratorRange.hpp:29
Definition: SparseTable.hpp:290
OPM_HOST_DEVICE Iterator & operator++()
Definition: SparseTable.hpp:297
OPM_HOST_DEVICE Iterator(const SparseTable &table, const int begin_row_index)
Definition: SparseTable.hpp:292
OPM_HOST_DEVICE row_type operator*() const
Definition: SparseTable.hpp:302
OPM_HOST_DEVICE bool operator!=(const Iterator &other)
Definition: SparseTable.hpp:311
OPM_HOST_DEVICE bool operator==(const Iterator &other)
Definition: SparseTable.hpp:306
Definition: SparseTable.hpp:117
OPM_HOST_DEVICE bool operator==(const SparseTable &other) const
Equality.
Definition: SparseTable.hpp:331
void swap(SparseTable< T > &other)
Swap contents for other SparseTable<T>
Definition: SparseTable.hpp:208
const T data(int i) const
Definition: SparseTable.hpp:349
typename row_type_helper< Storage< T > >::const_type row_type
Definition: SparseTable.hpp:268
void reserve(int exptd_nrows, int exptd_ndata)
Allocate storage for table of expected size.
Definition: SparseTable.hpp:201
typename row_type_helper< Storage< T > >::mutable_type mutable_row_type
Definition: SparseTable.hpp:269
const Storage< T > & dataStorage() const
Definition: SparseTable.hpp:361
void allocate(IntegerIter rowsize_beg, IntegerIter rowsize_end)
Definition: SparseTable.hpp:170
OPM_HOST_DEVICE int dataSize() const
Returns the number of data elements.
Definition: SparseTable.hpp:215
void clear()
Makes the table empty().
Definition: SparseTable.hpp:231
SparseTable(Storage< T > &&data, Storage< int > &&row_starts)
Definition: SparseTable.hpp:138
void appendRow(DataIter row_beg, DataIter row_end)
Appends a row to the table.
Definition: SparseTable.hpp:182
OPM_HOST_DEVICE bool empty() const
True if the table contains no rows.
Definition: SparseTable.hpp:189
const T * dataPtr() const
Definition: SparseTable.hpp:355
OPM_HOST_DEVICE int size() const
Returns the number of rows in the table.
Definition: SparseTable.hpp:195
const Storage< int > & rowStarts() const
Definition: SparseTable.hpp:367
SparseTable()
Default constructor. Yields an empty SparseTable.
Definition: SparseTable.hpp:120
void print(std::basic_ostream< charT, traits > &os) const
Definition: SparseTable.hpp:337
OPM_HOST_DEVICE row_type operator[](int row) const
Returns a row of the table.
Definition: SparseTable.hpp:272
void assign(DataIter data_beg, DataIter data_end, IntegerIter rowsize_beg, IntegerIter rowsize_end)
Definition: SparseTable.hpp:158
SparseTable(DataIter data_beg, DataIter data_end, IntegerIter rowsize_beg, IntegerIter rowsize_end)
Definition: SparseTable.hpp:131
OPM_HOST_DEVICE Iterator begin() const
Iterator access.
Definition: SparseTable.hpp:321
OPM_HOST_DEVICE int rowSize(int row) const
Returns the size of a table row.
Definition: SparseTable.hpp:221
OPM_HOST_DEVICE mutable_row_type operator[](int row)
Returns a mutable row of the table.
Definition: SparseTable.hpp:280
OPM_HOST_DEVICE Iterator end() const
Definition: SparseTable.hpp:325
Holds the implementation of the CpGrid as a pimple.
Definition: CellQuadrature.hpp:26
constexpr bool always_false_v
Definition: SparseTable.hpp:57
STL namespace.
Definition: SparseTable.hpp:63
T & reference
Definition: SparseTable.hpp:69
PoisonIterator()=default
reference operator*() const
Definition: SparseTable.hpp:74
friend bool operator==(const PoisonIterator &, const PoisonIterator &)
Definition: SparseTable.hpp:97
T value_type
Definition: SparseTable.hpp:66
pointer operator->() const
Definition: SparseTable.hpp:79
T * pointer
Definition: SparseTable.hpp:68
friend bool operator!=(const PoisonIterator &, const PoisonIterator &)
Definition: SparseTable.hpp:102
std::input_iterator_tag iterator_category
Definition: SparseTable.hpp:65
PoisonIterator operator++(int)
Definition: SparseTable.hpp:91
PoisonIterator & operator++()
Definition: SparseTable.hpp:85
std::ptrdiff_t difference_type
Definition: SparseTable.hpp:67
Definition: SparseTable.hpp:240
iterator_range< PoisonIterator< T > > const_type
Definition: SparseTable.hpp:241
mutable_iterator_range< PoisonIterator< T > > mutable_type
Definition: SparseTable.hpp:242
Definition: IteratorRange.hpp:56
Definition: IteratorRange.hpp:76