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