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 <initializer_list>
48#include <numeric>
49#include <ostream>
50#include <type_traits>
51#include <vector>
52
53namespace Opm
54{
55
56
57template<class>
58inline constexpr bool always_false_v = false;
59
60// Poison iterator is a helper class that will allow for compilation only when it is not used.
61// Its intention is to be used so that we can have a SparseTable of GPU data, which requires the
62// GPUBuffer intermediate storage type, which does not support iterators.
63template<class T>
65 // iterator traits so it type-checks where an iterator is required
66 using iterator_category = std::input_iterator_tag;
67 using value_type = T;
68 using difference_type = std::ptrdiff_t;
69 using pointer = T*;
70 using reference = T&;
71
72 PoisonIterator() = default;
73
74 // Dereference
76 static_assert(always_false_v<T>, "PoisonIterator: operator*() is not allowed.");
77 return *ptr_;
78 }
79
81 static_assert(always_false_v<T>, "PoisonIterator: operator->() is not allowed.");
82 return ptr_;
83 }
84
85 // Pre-increment
87 static_assert(always_false_v<T>, "PoisonIterator: operator++() is not allowed.");
88 return *this;
89 }
90
91 // Post-increment
93 static_assert(always_false_v<T>, "PoisonIterator: operator++(int) is not allowed.");
94 return *this;
95 }
96
97 // Equality/inequality
98 friend bool operator==(const PoisonIterator&, const PoisonIterator&) {
99 static_assert(always_false_v<T>, "PoisonIterator: operator== is not allowed.");
100 return true;
101 }
102
103 friend bool operator!=(const PoisonIterator&, const PoisonIterator&) {
104 static_assert(always_false_v<T>, "PoisonIterator: operator!= is not allowed.");
105 return false;
106 }
107
108private:
109 T* ptr_ = nullptr; // placeholder to keep types consistent
110};
111
116 template <typename T, template <typename, typename...> class Storage = std::vector>
118 {
119 public:
122 : row_start_(1, 0)
123 {
124 }
125
131 template <typename DataIter, typename IntegerIter>
132 SparseTable(DataIter data_beg, DataIter data_end,
133 IntegerIter rowsize_beg, IntegerIter rowsize_end)
134 : data_(data_beg, data_end)
135 {
136 setRowStartsFromSizes(rowsize_beg, rowsize_end);
137 }
138
139 SparseTable(Storage<T>&& data, Storage<int>&& row_starts)
140 : data_(std::move(data))
141 , row_start_(std::move(row_starts))
142 {
143 // removed for non-default template instantiations
144 // because we cannot access the zero'th element if Storage is a GpuBuffer
145 if constexpr (std::is_same_v<Storage<T>, std::vector<T>>) {
146 OPM_ERROR_IF(row_start_.size() == 0 || row_start_[0] != 0,
147 "Invalid row_start array");
148 }
149 }
150
151
153 SparseTable(std::initializer_list<std::initializer_list<T>> initlist) requires (std::is_same_v<Storage<T>, std::vector<T>>)
154 {
155 row_start_.push_back(0);
156 for (const auto& row : initlist) {
157 data_.insert(data_.end(), row);
158 row_start_.push_back(data_.size());
159 }
160 }
161
168 template <typename DataIter, typename IntegerIter>
169 void assign(DataIter data_beg, DataIter data_end,
170 IntegerIter rowsize_beg, IntegerIter rowsize_end)
172 data_.assign(data_beg, data_end);
173 setRowStartsFromSizes(rowsize_beg, rowsize_end);
180 template <typename IntegerIter>
181 void allocate(IntegerIter rowsize_beg, IntegerIter rowsize_end)
182 {
183 typedef typename Storage<T>::size_type sz_t;
184
185 sz_t ndata = std::accumulate(rowsize_beg, rowsize_end, sz_t(0));
186 data_.resize(ndata);
187 setRowStartsFromSizes(rowsize_beg, rowsize_end);
188 }
189
190
192 template <typename DataIter>
193 void appendRow(DataIter row_beg, DataIter row_end)
194 {
195 data_.insert(data_.end(), row_beg, row_end);
196 row_start_.push_back(data_.size());
197 }
198
201 {
202 return row_start_.size()==1;
203 }
204
207 {
208 return row_start_.size() - 1;
209 }
210
212 void reserve(int exptd_nrows, int exptd_ndata)
213 {
214 row_start_.reserve(exptd_nrows + 1);
215 data_.reserve(exptd_ndata);
216 }
217
219 void swap(SparseTable<T>& other)
220 {
221 row_start_.swap(other.row_start_);
222 data_.swap(other.data_);
223 }
224
227 {
228 return data_.size();
229 }
230
232 OPM_HOST_DEVICE int rowSize(int row) const
233 {
234#ifndef NDEBUG
235 OPM_ERROR_IF(row < 0 || row >= size(),
236 "Row index " + std::to_string(row) + " is out of range");
237#endif
238 return row_start_[row + 1] - row_start_[row];
239 }
240
242 void clear()
243 {
244 data_.clear();
245 row_start_.resize(1);
246 }
247
248 // Helper templates to select iterator range types only if (const_)iterator exists.
249 // Default: PoisonIterator (for non-traversable types)
250 template<class U, class = void>
254 };
255
256 // If Storage has const_iterator, use it (e.g. std::vector)
257 template<class U>
258 struct row_type_helper<U, std::void_t<typename U::const_iterator>> {
261 };
262
263#if HAVE_CUDA
264 // Specialization for GpuView: use its iterator
265 template<typename TT>
266 struct row_type_helper<gpuistl::GpuView<TT>> {
269 };
270
271 // Specialization for GpuBuffer: always PoisonIterator
272 template<typename TT>
273 struct row_type_helper<gpuistl::GpuBuffer<TT>> {
276 };
277#endif // HAVE_CUDA
278
279 using row_type = typename row_type_helper<Storage<T>>::const_type;
280 using mutable_row_type = typename row_type_helper<Storage<T>>::mutable_type;
281
284 {
285 assert(row >= 0 && row < size());
286 return row_type{data_.begin()+ row_start_[row],
287 data_.begin() + row_start_[row + 1]};
288 }
289
292 {
293 assert(row >= 0 && row < size());
294 return mutable_row_type{data_.begin() + row_start_[row],
295 data_.begin() + row_start_[row + 1]};
296 }
297
301 {
302 public:
303 OPM_HOST_DEVICE Iterator(const SparseTable& table, const int begin_row_index)
304 : table_(table)
305 , row_index_(begin_row_index)
306 {
307 }
309 {
310 ++row_index_;
311 return *this;
312 }
314 {
315 return table_[row_index_];
316 }
318 {
319 assert(&table_ == &other.table_);
320 return row_index_ == other.row_index_;
321 }
323 {
324 return !(*this == other);
325 }
326 private:
327 const SparseTable& table_;
328 int row_index_;
329 };
330
333 {
334 return Iterator(*this, 0);
335 }
337 {
338 return Iterator(*this, size());
339 }
340
342 OPM_HOST_DEVICE bool operator==(const SparseTable& other) const
343 {
344 return data_ == other.data_ && row_start_ == other.row_start_;
345 }
346
347 template<class charT, class traits>
348 void print(std::basic_ostream<charT, traits>& os) const
349 {
350 os << "Number of rows: " << size() << '\n';
351
352 os << "Row starts = [";
353 std::ranges::copy(row_start_, std::ostream_iterator<int>(os, " "));
354 os << "\b]\n";
355
356 os << "Data values = [";
357 std::ranges::copy(data_, std::ostream_iterator<T>(os, " "));
358 os << "\b]\n";
359 }
360 const T data(int i)const {
361 return data_[i];
362 }
363
364 // Get pointer to start of databuffer
365 // This is useful for getting access to the buffer itself so we can copy to GPU easily
366 const T* dataPtr() const
367 {
368 return data_.data();
369 }
370
371 // Access the data being stored directly (for instance used for copying to GPU)
372 const Storage<T>& dataStorage() const
373 {
374 return data_;
375 }
376
377 // Access indices of where all rows start
378 const Storage<int>& rowStarts() const
379 {
380 return row_start_;
381 }
382 private:
383 Storage<T> data_;
384 // Like in the compressed row sparse matrix format,
385 // row_start_.size() is equal to the number of rows + 1.
386 Storage<int> row_start_;
387
388 template <class IntegerIter>
389 void setRowStartsFromSizes(IntegerIter rowsize_beg, IntegerIter rowsize_end)
390 {
391#ifndef NDEBUG
392 // Check that all row sizes given are nonnegative.
393 for (auto it = rowsize_beg; it != rowsize_end; ++it) {
394 if (*it < 0) {
395 OPM_THROW(std::runtime_error, "Negative row size given.");
396 }
397 }
398#endif
399 // Since we do not store the row sizes, but cumulative row sizes,
400 // we have to create the cumulative ones.
401 int num_rows = rowsize_end - rowsize_beg;
402 row_start_.resize(num_rows + 1);
403 row_start_[0] = 0;
404 std::partial_sum(rowsize_beg, rowsize_end, row_start_.begin() + 1);
405 // Check that data_ and row_start_ match.
406 if (int(data_.size()) != row_start_.back()) {
407 OPM_THROW(std::runtime_error, "End of row start indices different from data size.");
408 }
409
410 }
411 };
412
413} // namespace Opm
414
415#if HAVE_CUDA
416namespace Opm::gpuistl {
417
418template <class T>
419auto copy_to_gpu(const SparseTable<T>& cpu_table)
420{
421 return SparseTable<T, GpuBuffer>(
422 GpuBuffer<T>(cpu_table.dataStorage()),
423 GpuBuffer<int>(cpu_table.rowStarts())
424 );
425}
426
427template <class T>
428auto make_view(SparseTable<T, GpuBuffer>& buffer_table)
429{
430 return SparseTable<T, GpuView>(
431 GpuView<T>(const_cast<T*>(buffer_table.dataStorage().data()),
432 buffer_table.dataStorage().size()),
433 GpuView<int>(const_cast<int*>(buffer_table.rowStarts().data()),
434 buffer_table.rowStarts().size())
435 );
436}
437
438} // namespace Opm::gpuistl
439#endif // HAVE_CUDA
440
441#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:301
OPM_HOST_DEVICE Iterator & operator++()
Definition: SparseTable.hpp:308
OPM_HOST_DEVICE Iterator(const SparseTable &table, const int begin_row_index)
Definition: SparseTable.hpp:303
OPM_HOST_DEVICE row_type operator*() const
Definition: SparseTable.hpp:313
OPM_HOST_DEVICE bool operator!=(const Iterator &other)
Definition: SparseTable.hpp:322
OPM_HOST_DEVICE bool operator==(const Iterator &other)
Definition: SparseTable.hpp:317
Definition: SparseTable.hpp:118
OPM_HOST_DEVICE bool operator==(const SparseTable &other) const
Equality.
Definition: SparseTable.hpp:342
void swap(SparseTable< T > &other)
Swap contents for other SparseTable<T>
Definition: SparseTable.hpp:219
const T data(int i) const
Definition: SparseTable.hpp:360
typename row_type_helper< Storage< T > >::const_type row_type
Definition: SparseTable.hpp:279
void reserve(int exptd_nrows, int exptd_ndata)
Allocate storage for table of expected size.
Definition: SparseTable.hpp:212
typename row_type_helper< Storage< T > >::mutable_type mutable_row_type
Definition: SparseTable.hpp:280
const Storage< T > & dataStorage() const
Definition: SparseTable.hpp:372
void allocate(IntegerIter rowsize_beg, IntegerIter rowsize_end)
Definition: SparseTable.hpp:181
OPM_HOST_DEVICE int dataSize() const
Returns the number of data elements.
Definition: SparseTable.hpp:226
void clear()
Makes the table empty().
Definition: SparseTable.hpp:242
SparseTable(Storage< T > &&data, Storage< int > &&row_starts)
Definition: SparseTable.hpp:139
void appendRow(DataIter row_beg, DataIter row_end)
Appends a row to the table.
Definition: SparseTable.hpp:193
OPM_HOST_DEVICE bool empty() const
True if the table contains no rows.
Definition: SparseTable.hpp:200
const T * dataPtr() const
Definition: SparseTable.hpp:366
SparseTable(std::initializer_list< std::initializer_list< T > > initlist)
Initializer list constructor for easy construction of small SparseTables.
Definition: SparseTable.hpp:153
OPM_HOST_DEVICE int size() const
Returns the number of rows in the table.
Definition: SparseTable.hpp:206
const Storage< int > & rowStarts() const
Definition: SparseTable.hpp:378
SparseTable()
Default constructor. Yields an empty SparseTable.
Definition: SparseTable.hpp:121
void print(std::basic_ostream< charT, traits > &os) const
Definition: SparseTable.hpp:348
OPM_HOST_DEVICE row_type operator[](int row) const
Returns a row of the table.
Definition: SparseTable.hpp:283
void assign(DataIter data_beg, DataIter data_end, IntegerIter rowsize_beg, IntegerIter rowsize_end)
Definition: SparseTable.hpp:169
SparseTable(DataIter data_beg, DataIter data_end, IntegerIter rowsize_beg, IntegerIter rowsize_end)
Definition: SparseTable.hpp:132
OPM_HOST_DEVICE Iterator begin() const
Iterator access.
Definition: SparseTable.hpp:332
OPM_HOST_DEVICE int rowSize(int row) const
Returns the size of a table row.
Definition: SparseTable.hpp:232
OPM_HOST_DEVICE mutable_row_type operator[](int row)
Returns a mutable row of the table.
Definition: SparseTable.hpp:291
OPM_HOST_DEVICE Iterator end() const
Definition: SparseTable.hpp:336
Holds the implementation of the CpGrid as a pimple.
Definition: CellQuadrature.hpp:26
constexpr bool always_false_v
Definition: SparseTable.hpp:58
STL namespace.
Definition: SparseTable.hpp:64
T & reference
Definition: SparseTable.hpp:70
PoisonIterator()=default
reference operator*() const
Definition: SparseTable.hpp:75
friend bool operator==(const PoisonIterator &, const PoisonIterator &)
Definition: SparseTable.hpp:98
T value_type
Definition: SparseTable.hpp:67
pointer operator->() const
Definition: SparseTable.hpp:80
T * pointer
Definition: SparseTable.hpp:69
friend bool operator!=(const PoisonIterator &, const PoisonIterator &)
Definition: SparseTable.hpp:103
std::input_iterator_tag iterator_category
Definition: SparseTable.hpp:66
PoisonIterator operator++(int)
Definition: SparseTable.hpp:92
PoisonIterator & operator++()
Definition: SparseTable.hpp:86
std::ptrdiff_t difference_type
Definition: SparseTable.hpp:68
Definition: SparseTable.hpp:251
iterator_range< PoisonIterator< T > > const_type
Definition: SparseTable.hpp:252
mutable_iterator_range< PoisonIterator< T > > mutable_type
Definition: SparseTable.hpp:253
Definition: IteratorRange.hpp:56
Definition: IteratorRange.hpp:76