opm-grid
Loading...
Searching...
No Matches
SparseTable.hpp
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 <opm/grid/utility/ErrorMacros.hpp>
39#include <opm/grid/utility/IteratorRange.hpp>
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>
63struct PoisonIterator {
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
74 reference operator*() const {
75 static_assert(always_false_v<T>, "PoisonIterator: operator*() is not allowed.");
76 return *ptr_;
77 }
78
79 pointer operator->() const {
80 static_assert(always_false_v<T>, "PoisonIterator: operator->() is not allowed.");
81 return ptr_;
82 }
83
84 // Pre-increment
85 PoisonIterator& operator++() {
86 static_assert(always_false_v<T>, "PoisonIterator: operator++() is not allowed.");
87 return *this;
88 }
89
90 // Post-increment
91 PoisonIterator operator++(int) {
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)
171 {
172 typedef typename Storage<T>::size_type sz_t;
173
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
189 OPM_HOST_DEVICE bool empty() const
190 {
191 return row_start_.size()==1;
192 }
193
195 OPM_HOST_DEVICE int size() const
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
215 OPM_HOST_DEVICE int dataSize() const
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>
241 using const_type = iterator_range<PoisonIterator<T>>;
242 using mutable_type = mutable_iterator_range<PoisonIterator<T>>;
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>> {
263 using const_type = iterator_range<PoisonIterator<TT>>;
264 using mutable_type = mutable_iterator_range<PoisonIterator<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
272 OPM_HOST_DEVICE row_type operator[](int row) const
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
280 OPM_HOST_DEVICE mutable_row_type operator[](int row)
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
289 class Iterator
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 }
297 OPM_HOST_DEVICE Iterator& operator++()
298 {
299 ++row_index_;
300 return *this;
301 }
302 OPM_HOST_DEVICE row_type operator*() const
303 {
304 return table_[row_index_];
305 }
306 OPM_HOST_DEVICE bool operator==(const Iterator& other)
307 {
308 assert(&table_ == &other.table_);
309 return row_index_ == other.row_index_;
310 }
311 OPM_HOST_DEVICE bool operator!=(const Iterator& other)
312 {
313 return !(*this == other);
314 }
315 private:
316 const SparseTable& table_;
317 int row_index_;
318 };
319
321 OPM_HOST_DEVICE Iterator begin() const
322 {
323 return Iterator(*this, 0);
324 }
325 OPM_HOST_DEVICE Iterator end() const
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
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
void reserve(int exptd_nrows, int exptd_ndata)
Allocate storage for table of expected size.
Definition SparseTable.hpp:201
void allocate(IntegerIter rowsize_beg, IntegerIter rowsize_end)
Request storage for table of given size.
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
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
OPM_HOST_DEVICE int size() const
Returns the number of rows in the table.
Definition SparseTable.hpp:195
SparseTable()
Default constructor. Yields an empty SparseTable.
Definition SparseTable.hpp:120
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)
Sets the table to contain the given data, organized into rows as indicated by the given row sizes.
Definition SparseTable.hpp:158
SparseTable(DataIter data_beg, DataIter data_end, IntegerIter rowsize_beg, IntegerIter rowsize_end)
A constructor taking all the data for the table and row sizes.
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
Holds the implementation of the CpGrid as a pimple.
Definition CellQuadrature.cpp:71
Definition SparseTable.hpp:240
Definition IteratorRange.hpp:56
Definition IteratorRange.hpp:76