Dune::Copasi
Loading...
Searching...
No Matches
cell_data.hh
Go to the documentation of this file.
1#ifndef DUNE_COPASI_GRID_CELL_DATA_HH
2#define DUNE_COPASI_GRID_CELL_DATA_HH
3
6
7#include <dune/grid/common/mcmgmapper.hh>
8
9#include <dune/grid/concepts/gridview.hh>
10
11#include <optional>
12#include <string>
13#include <vector>
14
15namespace Dune::Copasi {
16
23template<Dune::Concept::GridView GV, class T>
25{
26 // Index mapper for the grid view entities
28 using IndexSet = typename GV::IndexSet;
29
30 // Allow makeLeafGridViewCellData to see the contents of the level grid view case
32
33public:
34 using GridView = GV;
35
36 // Entity
37 using Entity = typename GridView::template Codim<0>::Entity;
38
40 : _index_mapper{ grid_view, mcmgElementLayout() }
41 {
42 // extract the level of the grid view if any
43 if (std::same_as<GridView, typename GridView::Grid::LevelGridView>) {
44 auto entity_it = grid_view.template begin<0>();
45 if (entity_it != grid_view.template end<0>())
46 _grid_view_level.emplace(0);
47 }
48 }
49
51
58 std::unique_ptr<CellData<typename GV::Grid::LeafGridView, T>> makeLeafGridViewCellData() const {
59 using LeafGridView = typename GV::Grid::LeafGridView;
60 if constexpr (std::same_as<GV, LeafGridView>) {
61 return std::make_unique<CellData<LeafGridView, T>>(*this);
62 } else {
63 if (_grid_view_level and _grid_view_level.value() != 0)
64 throw format_exception(
66 "Leaf grid view cell data can only be made out of other leaf grid view (copy) or a 0-th level grid view (projection)");
67
68 // copy values level grid view values into leaf grid view values
69 auto leaf_gv = _index_mapper.gridView().grid().leafGridView();
70 auto leaf_cd = std::make_unique<CellData<LeafGridView, T>>(leaf_gv);
71 leaf_cd->reserve(_keys.size());
72 auto lvl_cap = capacity();
73 auto leaf_cap = leaf_cd->capacity();
74 auto sz = size();
75 for (const auto& entity : elements(leaf_gv)) {
76 auto lvl_offset = index(entity) * lvl_cap;
77 auto leaf_offset = leaf_cd->index(entity) * leaf_cap;
78 for (std::size_t id = 0; id != sz; ++id) {
79 bool mask = leaf_cd->_cell_mask[leaf_offset + id] = _cell_mask[lvl_offset + id];
80 leaf_cd->_cell_data[leaf_offset + id] = mask ? _cell_data[lvl_offset + id] : std::numeric_limits<T>::quiet_NaN();
81 }
82 }
83 leaf_cd->_keys = _keys;
84 return leaf_cd;
85 }
86 }
87
89 std::size_t capacity() const noexcept { return _cell_data.size() / _index_mapper.size(); }
90
92 std::size_t size() const noexcept { return _keys.size(); }
93
95 std::size_t max_size() const noexcept { return _cell_data.max_size() / _index_mapper.size(); }
96
98 std::size_t gridview_size() const noexcept { return _index_mapper.size(); }
99
101 const std::vector<std::string>& keys() const noexcept { return _keys; }
102
104 // note that this does not honor the standard guarantees meaning that if an exception is thrown,
105 // there is no guarantee that the data will be unaffected
106 void reserve(std::size_t new_cap)
107 {
108 if (capacity() < new_cap)
109 realloc(new_cap);
110 }
111
113 {
114 if (auto sz = size(); sz != capacity())
115 realloc(sz);
116 }
117
118 // contiguous range
119 template<std::ranges::input_range R,
120 class Proj = std::identity,
121 std::indirect_unary_predicate<std::projected<std::ranges::iterator_t<R>, Proj>> Pred>
122 requires std::assignable_from<T&, std::ranges::range_value_t<R>>
123 void addData(std::string_view key, R&& r, Pred pred, Proj proj = {})
124 {
125 auto ei = size();
126 grow(size() + 1);
127 pushKey(key);
128 auto cap = capacity();
129 auto it = r.begin();
130 for (std::size_t i = 0; i != _index_mapper.size(); ++i, ++it) {
131 bool mask = _cell_mask[i * cap + ei] = std::invoke(pred, std::invoke(proj, *it));
132 _cell_data[i * cap + ei] = mask ? *it : std::numeric_limits<T>::quiet_NaN();
133 }
134 if (it != r.end())
135 throw format_exception(
137 "Range has a size of '{}', but there are '{}' entities in the container",
138 std::ranges::size(r),
139 _index_mapper.size());
140 }
141
142 template<std::ranges::input_range R>
143 requires std::assignable_from<T&, std::ranges::range_value_t<R>>
144 void addData(std::string_view key, R&& r)
145 {
146 addData(
147 key, std::forward<R>(r), [](auto&&) { return std::true_type{}; }, std::identity{});
148 }
149
150 // map range
151 template<std::ranges::input_range R,
152 class Proj = std::identity,
153 std::indirect_unary_predicate<std::projected<std::ranges::iterator_t<R>, Proj>> Pred>
154 requires std::assignable_from<T&, std::tuple_element_t<1, std::ranges::range_value_t<R>>>
155 void addData(std::string_view key, R&& r, Pred pred, Proj proj = {})
156 {
157 auto ei = size();
158 grow(size() + 1);
159 pushKey(key);
160 auto cap = capacity();
161 auto imsz = _index_mapper.size();
162 for (const auto& [i, val] : r) {
163 if(i >= _index_mapper.size())
164 throw format_exception(RangeError{}, "Key '{}' assinges a values in an index '{}' bigger than the size of the grid view '{}'", key, i, imsz);
165 bool mask = _cell_mask[i * cap + ei] = std::invoke(pred, std::invoke(proj, val));
166 _cell_data[i * cap + ei] = mask ? val : std::numeric_limits<T>::quiet_NaN();
167 }
168 }
169
170 // map range
171 template<std::ranges::input_range R>
172 requires std::assignable_from<T&, std::tuple_element_t<1, std::ranges::range_value_t<R>>>
173 void addData(std::string_view key, R&& r)
174 {
175 addData(
176 key, std::forward<R>(r), [](auto&&) { return std::true_type{}; }, std::identity{});
177 }
178
179 // copies data and data mask into buffers
181 std::vector<T>& cell_data,
182 std::vector<bool>& cell_mask) const
183 {
184 auto entity_index = index(entity);
185 auto cap = capacity();
186 auto sz = size();
187 cell_data.resize(sz);
188 cell_mask.resize(sz);
189 auto offset = entity_index * cap;
190 for (std::size_t id = 0; id != sz; ++id) {
191 bool mask = cell_mask[id] = _cell_mask[offset + id];
192 cell_data[id] = mask ? _cell_data[offset + id] : std::numeric_limits<T>::quiet_NaN();
193 }
194 }
195
196 // id is the index with respect to keys
197 std::optional<T> getData(std::size_t id,
199 {
200 auto entity_index = index(entity);
201 auto data_id = entity_index * capacity() + id;
202 return _cell_mask[data_id] ? std::make_optional<T>(_cell_data[data_id]) : std::nullopt;
203 }
204
205 // slower version
206 std::optional<T> getData(std::string_view key,
208 {
209 auto key_it = std::find(_keys.begin(), _keys.end(), key);
210 if (key_it == _keys.end())
211 throw format_exception(RangeError{}, "Key '{}' does not exist in cell data manager", key);
212 auto id = std::distance(_keys.begin(), key_it);
213 return getData(id, entity);
214 }
215
216private:
217 template<Concept::IndexableEntity<IndexSet> E>
218 auto index(const E& entity) const
219 {
220 if (_grid_view_level and (*_grid_view_level != entity.level())) {
221 E _entity = entity;
222 while (_entity.level() > *_grid_view_level) {
223 _entity = _entity.father();
224 }
225 if (_entity.level() != *_grid_view_level)
227 "Invoking a cell data manager with an entity of lower level than "
228 "the grid view attached to it is an invalid operation!");
229 return _index_mapper.index(_entity);
230 } else {
231 return _index_mapper.index(entity);
232 }
233 }
234
235 void pushKey(std::string_view key)
236 {
237 auto key_it = std::find(_keys.begin(), _keys.end(), key);
238 if (key_it != _keys.end())
239 throw format_exception(
240 InvalidStateException{}, "Key '{}' is already present in the cell data", key);
241 _keys.push_back(std::string{ key });
242 }
243
244 void grow(std::size_t new_size)
245 {
246 if (new_size < capacity())
247 return; // no-op
248 if (auto ms = max_size(); new_size > ms / 2)
249 reserve(ms); // maximum possible size
250 else
251 reserve(std::max(new_size, size() * 2)); // textbook growth factor of 2!
252 }
253
254 void realloc(std::size_t new_cap)
255 {
256 auto cap = capacity();
257 if (new_cap < size())
258 throw std::length_error{ "Requested raw capacity is smaller than current size" };
259 if (new_cap > max_size())
260 throw std::length_error{ "Requested capacity is bigger than maximum size" };
261
262 std::vector<T> new_cell_data;
263 new_cell_data.reserve(new_cap * _index_mapper.size());
264 auto data_begin = _cell_data.begin();
265
266 std::vector<bool> new_cell_mask;
267 new_cell_mask.reserve(new_cap * _index_mapper.size());
268 auto mask_begin = _cell_mask.begin();
269
270 for (std::size_t i = 0; i != _index_mapper.size(); ++i) {
271 // move data
272 auto data_end = std::next(data_begin, cap);
273 new_cell_data.insert(new_cell_data.end(),
274 std::make_move_iterator(data_begin),
275 std::make_move_iterator(data_end));
276 new_cell_data.resize(new_cap * (i + 1), std::numeric_limits<T>::quiet_NaN());
278 // move mask
279 auto mask_end = std::next(mask_begin, cap);
280 new_cell_mask.insert(new_cell_mask.end(),
281 std::make_move_iterator(mask_begin),
282 std::make_move_iterator(mask_end));
283 new_cell_mask.resize(new_cap * (i + 1), false);
285 }
286 std::swap(_cell_data, new_cell_data);
287 std::swap(_cell_mask, new_cell_mask);
288 }
289
290 IndexMapper _index_mapper;
291
292 // the level of the grid view, if none, leaf grid view or empty level grid view
293 std::optional<int> _grid_view_level;
294
295 std::vector<std::string> _keys;
296
297 std::vector<T> _cell_data;
298 std::vector<bool> _cell_mask;
299};
300
301} // namespace Dune::Copasi
302
303#endif // DUNE_COPASI_GRID_CELL_DATA_HH
Container for cell data of a grid view.
Definition cell_data.hh:25
void addData(std::string_view key, R &&r, Pred pred, Proj proj={})
Definition cell_data.hh:155
GV GridView
Definition cell_data.hh:34
CellData(GridView grid_view)
Definition cell_data.hh:39
void addData(std::string_view key, R &&r)
Definition cell_data.hh:144
void addData(std::string_view key, R &&r)
Definition cell_data.hh:173
std::size_t size() const noexcept
Number of elements per entity in the container.
Definition cell_data.hh:92
typename GridView::template Codim< 0 >::Entity Entity
Definition cell_data.hh:37
void getData(const Concept::IndexableEntity< IndexSet > auto &entity, std::vector< T > &cell_data, std::vector< bool > &cell_mask) const
Definition cell_data.hh:180
std::size_t max_size() const noexcept
Number of elements per entity that the container can ever hold container.
Definition cell_data.hh:95
std::optional< T > getData(std::string_view key, const Concept::IndexableEntity< IndexSet > auto &entity) const
Definition cell_data.hh:206
std::unique_ptr< CellData< typename GV::Grid::LeafGridView, T > > makeLeafGridViewCellData() const
creates a cell data object with a copy data for the leaf grid view
Definition cell_data.hh:58
std::size_t gridview_size() const noexcept
The size of the gridview - This gives the number of elements in the grid view.
Definition cell_data.hh:98
void addData(std::string_view key, R &&r, Pred pred, Proj proj={})
Definition cell_data.hh:123
const std::vector< std::string > & keys() const noexcept
Return the keys of the cell data.
Definition cell_data.hh:101
std::optional< T > getData(std::size_t id, const Concept::IndexableEntity< IndexSet > auto &entity) const
Definition cell_data.hh:197
void reserve(std::size_t new_cap)
Reservers new_cap elements per entity in the container.
Definition cell_data.hh:106
std::size_t capacity() const noexcept
Number of elements per entity that the container has currently allocated space for.
Definition cell_data.hh:89
void shrink_to_fit()
Definition cell_data.hh:112
Definition axis_names.hh:7
auto format_exception(Exception &&e, fmt::format_string< Args... > format, Args &&... args)
Definition exceptions.hh:23
constexpr bool is_bitflags_v
Alias for Bitflag indicator.
Definition bit_flags.hh:24