GridFormat 0.4.0
I/O-Library for grid-like data structures
Loading...
Searching...
No Matches
dune.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2// SPDX-License-Identifier: MIT
8#ifndef GRIDFORMAT_TRAITS_DUNE_HPP_
9#define GRIDFORMAT_TRAITS_DUNE_HPP_
10
11#include <ranges>
12#include <cassert>
13#include <algorithm>
14#include <tuple>
15// dune seems to not explicitly include this but uses std::int64_t.
16// With gcc-13 this leads to an error, maybe before gcc-13 the header
17// was included by some other standard library header...
18#include <cstdint>
19
20#ifdef GRIDFORMAT_IGNORE_DUNE_WARNINGS
21#pragma GCC diagnostic push
22#pragma GCC diagnostic ignored "-Wold-style-cast"
23#pragma GCC diagnostic ignored "-Wuseless-cast"
24#pragma GCC diagnostic ignored "-Warray-bounds"
25#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
26#pragma GCC diagnostic ignored "-Wnull-dereference"
27#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
28#endif // GRIDFORMAT_IGNORE_DUNE_WARNINGS
29#include <dune/common/fmatrix.hh>
30#include <dune/common/fvector.hh>
31#include <dune/geometry/type.hh>
32#include <dune/grid/common/gridview.hh>
33#include <dune/grid/common/gridenums.hh>
34#include <dune/grid/common/gridfactory.hh>
35#include <dune/grid/yaspgrid.hh>
36#ifdef GRIDFORMAT_IGNORE_DUNE_WARNINGS
37#pragma GCC diagnostic pop
38#endif // GRIDFORMAT_IGNORE_DUNE_WARNINGS
39
40#include <gridformat/common/ranges.hpp>
41#include <gridformat/common/exceptions.hpp>
42#include <gridformat/common/type_traits.hpp>
43
44#include <gridformat/grid/cell_type.hpp>
45#include <gridformat/grid/traits.hpp>
46
47namespace GridFormat::Traits {
48
49template<typename T, int R, int C>
50struct StaticSize<Dune::FieldMatrix<T, R, C>> {
51 static constexpr std::size_t value = R;
52};
53
54#ifndef DOXYGEN
55namespace DuneDetail {
56
57 inline int map_corner_index(const Dune::GeometryType& gt, int i) {
58 if (gt.isQuadrilateral()) {
59 assert(i < 4);
60 static constexpr int map[4] = {0, 1, 3, 2};
61 return map[i];
62 }
63 if (gt.isHexahedron()) {
64 assert(i < 8);
65 static constexpr int map[8] = {0, 1, 3, 2, 4, 5, 7, 6};
66 return map[i];
67 }
68 return i;
69 }
70
71 inline constexpr GridFormat::CellType cell_type(const Dune::GeometryType& gt) {
72 if (gt.isVertex()) return GridFormat::CellType::vertex;
73 if (gt.isLine()) return GridFormat::CellType::segment;
74 if (gt.isTriangle()) return GridFormat::CellType::triangle;
75 if (gt.isQuadrilateral()) return GridFormat::CellType::quadrilateral;
76 if (gt.isTetrahedron()) return GridFormat::CellType::tetrahedron;
77 if (gt.isHexahedron()) return GridFormat::CellType::hexahedron;
78 throw NotImplemented("Unknown Dune::GeometryType");
79 }
80
81 template<typename GridView>
82 using Element = typename GridView::template Codim<0>::Entity;
83
84 template<typename GridView>
85 using Vertex = typename GridView::template Codim<GridView::dimension>::Entity;
86
87} // namespace DuneDetail
88#endif // DOXYGEN
89
90
91template<typename Traits>
92struct Points<Dune::GridView<Traits>> {
93 static decltype(auto) get(const Dune::GridView<Traits>& grid_view) {
94 using GV = Dune::GridView<Traits>;
95 static constexpr int vertex_codim = GV::dimension;
96 return std::ranges::subrange(
97 grid_view.template begin<vertex_codim, Dune::InteriorBorder_Partition>(),
98 grid_view.template end<vertex_codim, Dune::InteriorBorder_Partition>()
99 );
100 }
101};
102
103template<typename Traits>
104struct Cells<Dune::GridView<Traits>> {
105 static decltype(auto) get(const Dune::GridView<Traits>& grid_view) {
106 return std::ranges::subrange(
107 grid_view.template begin<0, Dune::Interior_Partition>(),
108 grid_view.template end<0, Dune::Interior_Partition>()
109 );
110 }
111};
112
113template<typename Traits>
114struct NumberOfPoints<Dune::GridView<Traits>> {
115 static auto get(const Dune::GridView<Traits>& grid_view) {
116 static constexpr int point_codim = Dune::GridView<Traits>::dimension;
117 if (grid_view.comm().size() == 1)
118 return static_cast<std::size_t>(grid_view.size(point_codim));
119 return static_cast<std::size_t>(
120 Ranges::size(Points<Dune::GridView<Traits>>::get(grid_view))
121 );
122 }
123};
124
125template<typename Traits>
126struct NumberOfCells<Dune::GridView<Traits>> {
127 static auto get(const Dune::GridView<Traits>& grid_view) {
128 if (grid_view.comm().size() == 1)
129 return static_cast<std::size_t>(grid_view.size(0));
130 return static_cast<std::size_t>(
131 Ranges::size(Cells<Dune::GridView<Traits>>::get(grid_view))
132 );
133 }
134};
135
136template<typename Traits>
137struct NumberOfCellPoints<Dune::GridView<Traits>, DuneDetail::Element<Dune::GridView<Traits>>> {
138 static auto get(const Dune::GridView<Traits>&,
139 const DuneDetail::Element<Dune::GridView<Traits>>& cell) {
140 return cell.subEntities(Dune::GridView<Traits>::dimension);
141 }
142};
143
144template<typename Traits>
145struct CellPoints<Dune::GridView<Traits>, DuneDetail::Element<Dune::GridView<Traits>>> {
146 static decltype(auto) get(const Dune::GridView<Traits>&,
147 const DuneDetail::Element<Dune::GridView<Traits>>& element) {
148 static constexpr int dim = Dune::GridView<Traits>::dimension;
149 return std::views::iota(unsigned{0}, element.subEntities(dim)) | std::views::transform([&] (int i) {
150 return element.template subEntity<dim>(DuneDetail::map_corner_index(element.type(), i));
151 });
152 }
153};
154
155template<typename Traits>
156struct CellType<Dune::GridView<Traits>, DuneDetail::Element<Dune::GridView<Traits>>> {
157 static decltype(auto) get(const Dune::GridView<Traits>&,
158 const DuneDetail::Element<Dune::GridView<Traits>>& element) {
159 return DuneDetail::cell_type(element.type());
160 }
161};
162
163template<typename Traits>
164struct PointCoordinates<Dune::GridView<Traits>, DuneDetail::Vertex<Dune::GridView<Traits>>> {
165 static decltype(auto) get(const Dune::GridView<Traits>&,
166 const DuneDetail::Vertex<Dune::GridView<Traits>>& vertex) {
167 return vertex.geometry().center();
168 }
169};
170
171template<typename Traits>
172struct PointId<Dune::GridView<Traits>, DuneDetail::Vertex<Dune::GridView<Traits>>> {
173 static decltype(auto) get(const Dune::GridView<Traits>& grid_view,
174 const DuneDetail::Vertex<Dune::GridView<Traits>>& vertex) {
175 return grid_view.indexSet().index(vertex);
176 }
177};
178
179
180#ifndef DOXYGEN
181namespace DuneDetail {
182
183 template<typename T>
184 struct IsDuneYaspGrid : public std::false_type {};
185
186 template<int dim, typename Coords>
187 struct IsDuneYaspGrid<Dune::YaspGrid<dim, Coords>> : public std::true_type {
188 static constexpr bool uses_tp_coords = std::same_as<
189 Coords,
190 Dune::TensorProductCoordinates<typename Coords::ctype, dim>
191 >;
192 };
193
194 template<typename GridView>
195 inline constexpr bool is_yasp_grid_view = IsDuneYaspGrid<typename GridView::Grid>::value;
196
197 template<typename GridView> requires(is_yasp_grid_view<GridView>)
198 inline constexpr bool uses_tensor_product_coords = IsDuneYaspGrid<typename GridView::Grid>::uses_tp_coords;
199
200 template<typename ctype, int dim>
201 auto spacing_in(int direction, const Dune::EquidistantCoordinates<ctype, dim>& coords) {
202 return coords.meshsize(direction, 0);
203 }
204 template<typename ctype, int dim>
205 auto spacing_in(int direction, const Dune::EquidistantOffsetCoordinates<ctype, dim>& coords) {
206 return coords.meshsize(direction, 0);
207 }
208
209} // namespace DuneDetail
210#endif // DOXYGEN
211
212
213// Register YaspGrid as structured grid
214template<typename Traits> requires(DuneDetail::is_yasp_grid_view<Dune::GridView<Traits>>)
215struct Extents<Dune::GridView<Traits>> {
216 static auto get(const Dune::GridView<Traits>& grid_view) {
217 const auto level = std::ranges::begin(Cells<Dune::GridView<Traits>>::get(grid_view))->level();
218 const auto& grid_level = *grid_view.grid().begin(level);
219 const auto& interior_grid = grid_level.interior[0];
220 const auto& gc = *interior_grid.dataBegin();
221
222 static constexpr int dim = Traits::Grid::dimension;
223 std::array<std::size_t, dim> result;
224 for (int i = 0; i < Traits::Grid::dimension; ++i)
225 result[i] = gc.max(i) - gc.min(i) + 1;
226 return result;
227 }
228};
229
230template<typename Traits, typename Entity> requires(DuneDetail::is_yasp_grid_view<Dune::GridView<Traits>>)
231struct Location<Dune::GridView<Traits>, Entity> {
232 static auto get(const Dune::GridView<Traits>& grid_view, const Entity& entity) {
233 auto const& grid_level = *grid_view.grid().begin(entity.level());
234 auto const& interior = grid_level.interior[0];
235 auto const& extent_bounds = *interior.dataBegin();
236
237 auto result = entity.impl().transformingsubiterator().coord();
238 for (int i = 0; i < Dune::GridView<Traits>::dimension; ++i)
239 result[i] -= extent_bounds.min(i);
240 return result;
241 }
242};
243
244template<typename Traits> requires(DuneDetail::is_yasp_grid_view<Dune::GridView<Traits>>)
245struct Origin<Dune::GridView<Traits>> {
246 static auto get(const Dune::GridView<Traits>& grid_view) {
247 const auto level = std::ranges::begin(Cells<Dune::GridView<Traits>>::get(grid_view))->level();
248 auto const& grid_level = *grid_view.grid().begin(level);
249 auto const& interior = grid_level.interior[0];
250 auto const& extent_bounds = *interior.dataBegin();
251
252 std::array<typename Traits::Grid::ctype, Traits::Grid::dimension> result;
253 for (int i = 0; i < Traits::Grid::dimension; ++i)
254 result[i] = grid_level.coords.coordinate(i, extent_bounds.min(i));
255 return result;
256 }
257};
258
259template<typename Traits>
260 requires(DuneDetail::is_yasp_grid_view<Dune::GridView<Traits>> and
261 !DuneDetail::uses_tensor_product_coords<Dune::GridView<Traits>>) // spacing not uniquely defined for tpcoords
262struct Spacing<Dune::GridView<Traits>> {
263 static auto get(const Dune::GridView<Traits>& grid_view) {
264 const auto level = std::ranges::begin(Cells<Dune::GridView<Traits>>::get(grid_view))->level();
265 auto const& grid_level = *grid_view.grid().begin(level);
266
267 std::array<typename Traits::Grid::ctype, Traits::Grid::dimension> result;
268 for (int i = 0; i < Traits::Grid::dimension; ++i)
269 result[i] = DuneDetail::spacing_in(i, grid_level.coords);
270 return result;
271 }
272};
273
274template<typename Traits> requires(DuneDetail::is_yasp_grid_view<Dune::GridView<Traits>>)
275struct Ordinates<Dune::GridView<Traits>> {
276 static auto get(const Dune::GridView<Traits>& grid_view, int direction) {
277 const auto level = std::ranges::begin(Cells<Dune::GridView<Traits>>::get(grid_view))->level();
278 auto const& grid_level = *grid_view.grid().begin(level);
279 auto const& interior = grid_level.interior[0];
280 auto const& extent_bounds = *interior.dataBegin();
281
282 const auto num_point_ordinates = extent_bounds.max(direction) - extent_bounds.min(direction) + 2;
283 std::vector<typename Traits::Grid::ctype> ordinates(num_point_ordinates);
284 for (int i = 0; i < num_point_ordinates; ++i)
285 ordinates[i] = grid_level.coords.coordinate(direction, extent_bounds.min(direction) + i);
286 return ordinates;
287 }
288};
289
290} // namespace GridFormat::Traits
291
292
293// Higher-order output is only available with dune-localfunctions
294#if GRIDFORMAT_HAVE_DUNE_LOCALFUNCTIONS
295
296#include <algorithm>
297#include <iterator>
298#include <utility>
299#include <ranges>
300#include <cassert>
301#include <type_traits>
302#include <unordered_map>
303#include <map>
304
305#ifdef GRIDFORMAT_IGNORE_DUNE_WARNINGS
306#pragma GCC diagnostic push
307#pragma GCC diagnostic ignored "-Wold-style-cast"
308#pragma GCC diagnostic ignored "-Wtype-limits"
309#endif // GRIDFORMAT_IGNORE_DUNE_WARNINGS
310#include <dune/geometry/referenceelements.hh>
311#include <dune/grid/common/mcmgmapper.hh>
312#include <dune/localfunctions/lagrange/equidistantpoints.hh>
313#ifdef GRIDFORMAT_IGNORE_DUNE_WARNINGS
314#pragma GCC diagnostic pop
315#endif // GRIDFORMAT_IGNORE_DUNE_WARNINGS
316
317#include <gridformat/common/reserved_vector.hpp>
318#include <gridformat/common/type_traits.hpp>
319#include <gridformat/common/precision.hpp>
320#include <gridformat/common/concepts.hpp>
322#include <gridformat/grid.hpp>
323
324
325namespace GridFormat {
326
327// create this alias s.t. we can explicitly
328// address the original Dune namespace
329namespace DUNE = Dune;
330
331namespace Dune {
332
333#ifndef DOXYGEN
334namespace LagrangeDetail {
335
336 inline int dune_to_gfmt_sub_entity(const DUNE::GeometryType& gt, int i, int codim) {
337 if (gt.isTriangle()) {
338 if (codim == 1) {
339 assert(i < 3);
340 static constexpr int map[3] = {0, 2, 1};
341 return map[i];
342 }
343 }
344 if (gt.isQuadrilateral()) {
345 if (codim == 2) {
346 assert(i < 4);
347 static constexpr int map[4] = {0, 1, 3, 2};
348 return map[i];
349 }
350 if (codim == 1) {
351 assert(i < 4);
352 static constexpr int map[4] = {3, 1, 0, 2};
353 return map[i];
354 }
355 }
356 if (gt.isTetrahedron()) {
357 if (codim == 2) {
358 assert(i < 6);
359 static constexpr int map[6] = {0, 2, 1, 3, 4, 5};
360 return map[i];
361 }
362 if (codim == 1) {
363 assert(i < 4);
364 static constexpr int map[4] = {3, 0, 2, 1};
365 return map[i];
366 }
367 }
368 if (gt.isHexahedron()) {
369 if (codim == 3) {
370 assert(i < 8);
371 static constexpr int map[8] = {0, 1, 3, 2, 4, 5, 7, 6};
372 return map[i];
373 }
374 if (codim == 2) {
375 assert(i < 12);
376 static constexpr int map[12] = {8, 9, 11, 10, 3, 1, 0, 2, 7, 5, 4, 6};
377 return map[i];
378 }
379 }
380 return i;
381 }
382
383 inline constexpr GridFormat::CellType cell_type(const DUNE::GeometryType& gt) {
384 if (gt.isLine()) return GridFormat::CellType::lagrange_segment;
385 if (gt.isTriangle()) return GridFormat::CellType::lagrange_triangle;
386 if (gt.isQuadrilateral()) return GridFormat::CellType::lagrange_quadrilateral;
387 if (gt.isTetrahedron()) return GridFormat::CellType::lagrange_tetrahedron;
388 if (gt.isHexahedron()) return GridFormat::CellType::lagrange_hexahedron;
389 throw NotImplemented("Unsupported Dune::GeometryType");
390 }
391
392 // Exposes the lagrange points of a geometry in gridformat ordering
393 template<typename GridView>
394 class LocalPoints {
395 // reserve space for third-order hexahedra
396 static constexpr std::size_t reserved_size = 64;
397
398 public:
399 using PointSet = DUNE::EquidistantPointSet<typename GridView::ctype, GridView::dimension>;
400 using Point = typename PointSet::LagrangePoint;
401
402 explicit LocalPoints(unsigned int order)
403 : _points(order)
404 {}
405
406 void build(const DUNE::GeometryType& geo_type) {
407 if (geo_type.dim() != GridView::dimension)
408 throw ValueError("Dimension of given geometry does not match the grid");
409 _points.build(geo_type);
410 _setup_sorted_indices(geo_type);
411 }
412
413 std::size_t size() const {
414 return _points.size();
415 }
416
417 const Point& at(std::size_t i) const {
418 return _points[_sorted_indices.at(i)];
419 }
420
421 std::ranges::range auto get() const {
422 return _sorted_indices | std::views::transform([&] (unsigned int i) {
423 return _points[i];
424 });
425 }
426
427 private:
428 void _setup_sorted_indices(const DUNE::GeometryType& geo_type) {
429 std::ranges::copy(
430 std::views::iota(unsigned{0}, static_cast<unsigned int>(_points.size())),
431 std::back_inserter(_sorted_indices)
432 );
433 std::ranges::sort(_sorted_indices, [&] (unsigned int i1, unsigned int i2) {
434 const auto& key1 = _points[i1].localKey();
435 const auto& key2 = _points[i2].localKey();
436 using LagrangeDetail::dune_to_gfmt_sub_entity;
437 if (key1.codim() == key2.codim()) {
438 const auto mapped1 = dune_to_gfmt_sub_entity(geo_type, key1.subEntity(), key1.codim());
439 const auto mapped2 = dune_to_gfmt_sub_entity(geo_type, key2.subEntity(), key2.codim());
440 return mapped1 == mapped2 ? key1.index() < key2.index() : mapped1 < mapped2;
441 }
442 return _points[i1].localKey().codim() > _points[i2].localKey().codim();
443 });
444 }
445
446 PointSet _points;
447 ReservedVector<unsigned int, reserved_size> _sorted_indices;
448 };
449
450 class PointMapper {
451 public:
452 template<typename GridView>
453 explicit PointMapper(const GridView& grid_view) {
454 _codim_to_global_indices.resize(GridView::dimension + 1);
455 for (int codim = 0; codim < GridView::dimension + 1; ++codim)
456 _codim_to_global_indices[codim].resize(grid_view.size(codim));
457 }
458
459 struct Key {
460 unsigned int codim;
461 std::size_t global_index;
462 unsigned int sub_index;
463 };
464
465 bool contains(const Key& key) const {
466 const auto& entity_dofs = _codim_to_global_indices[key.codim][key.global_index];
467 if (entity_dofs.size() <= key.sub_index)
468 return false;
469 return entity_dofs[key.sub_index] != -1;
470 }
471
472 void insert(const Key& key, std::size_t index) {
473 auto& entity_dofs = _codim_to_global_indices[key.codim][key.global_index];
474 if (entity_dofs.size() < key.sub_index + 1)
475 entity_dofs.resize(key.sub_index + 1, -1);
476 entity_dofs[key.sub_index] = static_cast<std::int64_t>(index);
477 }
478
479 std::size_t get(const Key& key) const {
480 assert(_codim_to_global_indices[key.codim][key.global_index].size() > key.sub_index);
481 auto index = _codim_to_global_indices[key.codim][key.global_index][key.sub_index];
482 assert(index != -1);
483 return static_cast<std::size_t>(index);
484 }
485
486 void clear() {
487 _codim_to_global_indices.clear();
488 }
489
490 private:
491 std::vector< // codim
492 std::vector< // entity index
493 ReservedVector<std::int64_t, 20> // sub-entity index to global indices
494 >
495 > _codim_to_global_indices;
496 };
497
498} // namespace LagrangeDetail
499#endif // DOXYGEN
500
501
508template<typename GV>
510 using Element = typename GV::Grid::template Codim<0>::Entity;
511 using ElementGeometry = typename Element::Geometry;
512 using GlobalCoordinate = typename ElementGeometry::GlobalCoordinate;
513 using LocalCoordinate = typename ElementGeometry::LocalCoordinate;
514
515 using LocalPoints = LagrangeDetail::LocalPoints<GV>;
516 using Mapper = DUNE::MultipleCodimMultipleGeomTypeMapper<GV>;
517 static constexpr int dim = GV::dimension;
518
519 template<typename Coord>
520 struct P {
521 std::size_t index;
522 Coord coordinates;
523 };
524
525 using _GlobalPoint = P<GlobalCoordinate>;
526 using _LocalPoint = P<LocalCoordinate>;
527
528 public:
529 using GridView = GV;
530 using Position = GlobalCoordinate;
531 using Cell = Element;
532 using Point = _GlobalPoint;
533 using LocalPoint = _LocalPoint;
534
535 explicit LagrangePolynomialGrid(const GridView& grid_view, unsigned int order = 1)
536 : _grid_view{grid_view}
537 , _order{order} {
538 if (order < 1)
539 throw InvalidState("Order must be >= 1");
540 update(grid_view);
541 }
542
543 void update(const GridView& grid_view) {
544 clear();
545 _grid_view = grid_view;
546 _make_codim_mappers();
547 _update_local_points();
548 _update_mesh();
549 }
550
551 void clear() {
552 _codim_to_mapper.clear();
553 _local_points.clear();
554 _points.clear();
555 _cells.clear();
556 }
557
558 std::size_t number_of_cells() const {
559 return _cells.empty() ? 0 : Traits::NumberOfCells<GridView>::get(_grid_view);
560 }
561
562 std::size_t number_of_points() const {
563 return _points.size();
564 }
565
566 std::size_t number_of_points(const Element& element) const {
567 return _local_points.at(element.type()).size();
568 }
569
570 std::ranges::range auto cells() const {
571 return Traits::Cells<GridView>::get(_grid_view);
572 }
573
574 std::ranges::range auto points() const {
575 return std::views::iota(std::size_t{0}, _points.size())
576 | std::views::transform([&] (std::size_t idx) {
577 return Point{idx, _points[idx]};
578 });
579 }
580
581 std::ranges::range auto points(const Element& e) const {
582 const auto& corners = _cells[_codim_to_mapper[0].index(e)];
583 return std::views::iota(std::size_t{0}, corners.size())
584 | std::views::transform([&] (std::size_t i) {
585 return Point{
586 .index = corners[i],
587 .coordinates = _points[corners[i]]
588 };
589 });
590 }
591
592 const GridView& grid_view() const {
593 return _grid_view;
594 }
595
596 private:
597 void _update_local_points() {
598 for (const auto& gt : _grid_view.indexSet().types(0)) {
599 _local_points.emplace(gt, _order);
600 _local_points.at(gt).build(gt);
601 }
602 }
603
604 void _make_codim_mappers() {
605 _codim_to_mapper.reserve(dim + 1);
606 _codim_to_mapper.emplace_back(Mapper{_grid_view, DUNE::mcmgLayout(DUNE::Codim<0>{})});
607 if constexpr (int(GridView::dimension) >= 1)
608 _codim_to_mapper.emplace_back(Mapper{_grid_view, DUNE::mcmgLayout(DUNE::Codim<1>{})});
609 if constexpr (int(GridView::dimension) >= 2)
610 _codim_to_mapper.emplace_back(Mapper{_grid_view, DUNE::mcmgLayout(DUNE::Codim<2>{})});
611 if constexpr (int(GridView::dimension) == 3)
612 _codim_to_mapper.emplace_back(Mapper{_grid_view, DUNE::mcmgLayout(DUNE::Codim<3>{})});
613 }
614
615 void _update_mesh() {
616 LagrangeDetail::PointMapper point_mapper{_grid_view};
617 std::size_t dof_index = 0;
618 _cells.resize(_grid_view.size(0));
619 for (const auto& element : Traits::Cells<GridView>::get(_grid_view)) {
620 const auto& local_points = _local_points.at(element.type()).get();
621 const auto& element_geometry = element.geometry();
622 const auto element_index = _codim_to_mapper[0].index(element);
623 _cells[element_index].reserve(local_points.size());
624 for (const auto& local_point : local_points) {
625 const auto& localKey = local_point.localKey();
626 const typename LagrangeDetail::PointMapper::Key key{
627 .codim = localKey.codim(),
628 .global_index = _codim_to_mapper[localKey.codim()].subIndex(
629 element, localKey.subEntity(), localKey.codim()
630 ),
631 .sub_index = localKey.index()
632 };
633 if (!point_mapper.contains(key)) {
634 point_mapper.insert(key, dof_index);
635 _cells[element_index].push_back(dof_index);
636 _points.push_back(element_geometry.global(local_point.point()));
637 dof_index++;
638 } else {
639 _cells[element_index].push_back(point_mapper.get(key));
640 }
641 }
642 }
643 }
644
645 GridView _grid_view;
646 unsigned int _order;
647 std::vector<Mapper> _codim_to_mapper;
648 std::map<DUNE::GeometryType, LocalPoints> _local_points;
649 std::vector<GlobalCoordinate> _points;
650 std::vector<std::vector<std::size_t>> _cells;
651};
652
653namespace Traits {
654
655template<typename GV>
656struct GridView {
657 using type = GV;
658 static const auto& get(const GV& gv) {
659 return gv;
660 }
661};
662
663template<typename GV>
665 using type = GV;
666 static const auto& get(const LagrangePolynomialGrid<GV>& grid) {
667 return grid.grid_view();
668 }
669};
670
671} // namespace Traits
672} // namespace Dune
673
674
675namespace Traits {
676
677template<typename GridView>
678struct Points<Dune::LagrangePolynomialGrid<GridView>> {
679 static auto get(const Dune::LagrangePolynomialGrid<GridView>& mesh) {
680 return mesh.points();
681 }
682};
683
684template<typename GridView>
685struct Cells<Dune::LagrangePolynomialGrid<GridView>> {
686 static auto get(const Dune::LagrangePolynomialGrid<GridView>& mesh) {
687 return mesh.cells();
688 }
689};
690
691template<typename GridView>
692struct NumberOfPoints<Dune::LagrangePolynomialGrid<GridView>> {
693 static auto get(const Dune::LagrangePolynomialGrid<GridView>& mesh) {
694 return mesh.number_of_points();
695 }
696};
697
698template<typename GridView>
699struct NumberOfCells<Dune::LagrangePolynomialGrid<GridView>> {
700 static auto get(const Dune::LagrangePolynomialGrid<GridView>& mesh) {
701 return mesh.number_of_cells();
702 }
703};
704
705template<typename GridView>
706struct NumberOfCellPoints<Dune::LagrangePolynomialGrid<GridView>,
707 typename Dune::LagrangePolynomialGrid<GridView>::Cell> {
708 static auto get(const Dune::LagrangePolynomialGrid<GridView>& mesh,
709 const typename Dune::LagrangePolynomialGrid<GridView>::Cell& cell) {
710 return mesh.number_of_points(cell);
711 }
712};
713
714template<typename GridView>
715struct CellPoints<Dune::LagrangePolynomialGrid<GridView>,
716 typename Dune::LagrangePolynomialGrid<GridView>::Cell> {
717 static auto get(const Dune::LagrangePolynomialGrid<GridView>& mesh,
718 const typename Dune::LagrangePolynomialGrid<GridView>::Cell& cell) {
719 return mesh.points(cell);
720 }
721};
722
723template<typename GridView>
724struct CellType<Dune::LagrangePolynomialGrid<GridView>,
725 typename Dune::LagrangePolynomialGrid<GridView>::Cell> {
726 static auto get(const Dune::LagrangePolynomialGrid<GridView>&,
727 const typename Dune::LagrangePolynomialGrid<GridView>::Cell& cell) {
728 return Dune::LagrangeDetail::cell_type(cell.type());
729 }
730};
731
732template<typename GridView>
733struct PointCoordinates<Dune::LagrangePolynomialGrid<GridView>,
734 typename Dune::LagrangePolynomialGrid<GridView>::Point> {
735 static const auto& get(const Dune::LagrangePolynomialGrid<GridView>&,
736 const typename Dune::LagrangePolynomialGrid<GridView>::Point& point) {
737 return point.coordinates;
738 }
739};
740
741template<typename GridView>
742struct PointId<Dune::LagrangePolynomialGrid<GridView>,
743 typename Dune::LagrangePolynomialGrid<GridView>::Point> {
744 static auto get(const Dune::LagrangePolynomialGrid<GridView>&,
745 const typename Dune::LagrangePolynomialGrid<GridView>::Point& point) {
746 return point.index;
747 }
748};
749
750} // namespace Traits
751
752
753namespace Dune {
754namespace Concepts {
755
756template<typename T, typename GridView>
757concept Function = requires(const T& f, const typename GridView::template Codim<0>::Entity& element) {
758 { localFunction(f) };
759 { localFunction(f).bind(element) };
760 { localFunction(f)(element.geometry().center()) };
761};
762
763} // namespace Concepts
764
765#ifndef DOXYGEN
766namespace FunctionDetail {
767
768 template<typename Function, typename GridView>
769 using RangeType = std::invoke_result_t<
770 typename std::remove_cvref_t<Function>::LocalFunction,
771 typename GridView::template Codim<0>::Entity::Geometry::LocalCoordinate
772 >;
773
774 template<typename Function, typename GridView>
775 using RangeScalar = FieldScalar<RangeType<Function, GridView>>;
776
777} // FunctionDetail
778#endif // DOXYGEN
779
786template<typename _Function, typename Grid, GridFormat::Concepts::Scalar T>
787 requires(Concepts::Function<_Function, typename Dune::Traits::GridView<Grid>::type>)
789 using Function = std::remove_cvref_t<_Function>;
790 using GridView = typename Dune::Traits::GridView<Grid>::type;
791 using Element = typename GridView::template Codim<0>::Entity;
792 using ElementGeometry = typename Element::Geometry;
793
794 static constexpr bool is_higher_order = std::is_same_v<Grid, LagrangePolynomialGrid<GridView>>;
795
796 public:
797 template<typename F>
798 requires(std::is_same_v<std::remove_cvref_t<F>, Function>)
799 explicit FunctionField(F&& function,
800 const Grid& grid,
801 const Precision<T>& = {},
802 bool cellwise_constant = false)
803 : _function{std::forward<F>(function)}
804 , _grid{grid}
805 , _cellwise_constant{cellwise_constant} {
806 if constexpr (requires { function.basis(); }) {
807 static_assert(std::is_same_v<typename Function::Basis::GridView, GridView>);
808 if (&function.basis().gridView().grid() != &Dune::Traits::GridView<Grid>::get(_grid).grid())
809 throw ValueError("Function and mesh do not use the same underlying grid");
810 }
811 }
812
813 private:
814 MDLayout _layout() const override {
815 return MDLayout{{
816 _cellwise_constant ? GridFormat::Traits::NumberOfCells<Grid>::get(_grid)
817 : GridFormat::Traits::NumberOfPoints<Grid>::get(_grid)
818 }}.template with_sub_layout_from<FunctionDetail::RangeType<Function, GridView>>();
819 }
820
821 DynamicPrecision _precision() const override {
822 return {Precision<T>{}};
823 }
824
825 Serialization _serialized() const override {
826 const auto layout = _layout();
827 const auto num_entries = layout.number_of_entries();
828 const auto num_entries_per_value = layout.dimension() == 1 ? 1 : layout.number_of_entries(1);
829
830 Serialization result(num_entries*sizeof(T));
831 auto out_data = result.template as_span_of<T>();
832
833 using GridFormat::Traits::Cells;
834 if (_cellwise_constant) {
835 std::size_t count = 0;
836 auto local_function = localFunction(_function);
837 for (const auto& element : Cells<Grid>::get(_grid)) {
838 local_function.bind(element);
839 const auto& elem_geo = element.geometry();
840 const auto& local_pos = elem_geo.local(elem_geo.center());
841 std::size_t offset = (count++)*num_entries_per_value;
842 _copy_values(local_function(local_pos), out_data, offset);
843 }
844 } else {
845 _fill_point_values(out_data, num_entries_per_value);
846 }
847
848 return result;
849 }
850
851 void _fill_point_values(std::span<T> out_data, std::size_t num_entries_per_value) const
852 requires(!is_higher_order) {
853 using GridFormat::Traits::Cells;
854 using GridFormat::Traits::CellPoints;
855 using GridFormat::Traits::PointCoordinates;
856 using GridFormat::Traits::PointId;
857 using GridFormat::Traits::NumberOfPoints;
858
859 auto local_function = localFunction(_function);
860 auto point_id_to_running_idx = make_point_id_map(_grid);
861 std::vector<bool> handled(NumberOfPoints<Grid>::get(_grid), false);
862
863 std::ranges::for_each(Cells<Grid>::get(_grid), [&] <typename C> (const C& element) {
864 const auto& element_geometry = element.geometry();
865 local_function.bind(element);
866 std::ranges::for_each(CellPoints<Grid, Element>::get(_grid, element), [&] <typename P> (const P& point) {
867 const auto point_id = PointId<Grid, P>::get(_grid, point);
868 const auto running_idx = point_id_to_running_idx.at(point_id);
869 if (!handled[running_idx]) {
870 const auto local_pos = element_geometry.local(PointCoordinates<Grid, P>::get(_grid, point));
871 std::size_t offset = running_idx*num_entries_per_value;
872 _copy_values(local_function(local_pos), out_data, offset);
873 }
874 handled[running_idx] = true;
875 });
876 });
877 }
878
879 void _fill_point_values(std::span<T> out_data, std::size_t num_entries_per_value) const
880 requires(is_higher_order) {
881 using GridFormat::Traits::Cells;
882 using GridFormat::Traits::CellPoints;
883 auto local_function = localFunction(_function);
884 std::vector<bool> handled(_grid.number_of_points(), false);
885 std::ranges::for_each(Cells<Grid>::get(_grid), [&] <typename C> (const C& element) {
886 const auto& element_geometry = element.geometry();
887 local_function.bind(element);
888 std::ranges::for_each(_grid.points(element), [&] <typename P> (const P& point) {
889 if (!handled[point.index]) {
890 const auto local_pos = element_geometry.local(point.coordinates);
891 std::size_t offset = point.index*num_entries_per_value;
892 _copy_values(local_function(local_pos), out_data, offset);
893 }
894 handled[point.index] = true;
895 });
896 });
897 }
898
899 template<std::ranges::range R>
900 void _copy_values(R&& range, std::span<T> out, std::size_t& offset) const {
901 std::ranges::for_each(range, [&] (const auto& entry) {
902 _copy_values(entry, out, offset);
903 });
904 }
905
906 template<GridFormat::Concepts::Scalar S>
907 void _copy_values(const S value, std::span<T> out, std::size_t& offset) const {
908 out[offset++] = static_cast<T>(value);
909 }
910
911 _Function _function;
912 const Grid& _grid;
913 bool _cellwise_constant;
914};
915
916
917template<typename F, typename G, typename T = FunctionDetail::RangeScalar<F, typename Traits::GridView<G>::type>>
918 requires(std::is_lvalue_reference_v<F>)
919FunctionField(F&&, const G&, const Precision<T>& = {}, bool = false) -> FunctionField<
920 std::add_lvalue_reference_t<std::add_const_t<std::remove_reference_t<F>>>, G, T
921>;
922
923template<typename F, typename G, typename T = FunctionDetail::RangeScalar<F, typename Traits::GridView<G>::type>>
924 requires(!std::is_lvalue_reference_v<F>)
925FunctionField(F&&, const G&, const Precision<T>& = {}, bool = false) -> FunctionField<std::remove_cvref_t<F>, G, T>;
926
927
928#ifndef DOXYGEN
929template<typename T> struct IsLagrangeGrid : public std::false_type {};
930template<typename GV> struct IsLagrangeGrid<LagrangePolynomialGrid<GV>> : public std::true_type {};
931
932namespace FunctionDetail {
933 template<typename F, typename W, typename T>
934 void set_function(F&& f, W& w, const std::string& name, const Precision<T>& prec, bool is_cellwise) {
935 if (is_cellwise)
936 w.set_cell_field(name, FunctionField{std::forward<F>(f), w.grid(), prec, true});
937 else
938 w.set_point_field(name, FunctionField{std::forward<F>(f), w.grid(), prec, false});
939 }
940
941 template<typename F, typename W>
942 void set_function(F&& f, W& w, const std::string& name, bool is_cellwise) {
943 using GV = Dune::Traits::GridView<typename W::Grid>::type;
944 using T = RangeScalar<F, GV>;
945 set_function(std::forward<F>(f), w, name, Precision<T>{}, is_cellwise);
946 }
947} // namespace FunctionDetail
948#endif //DOXYGEN
949
955template<typename Function, typename Writer>
956void set_point_function(Function&& f, Writer& writer, const std::string& name) {
957 FunctionDetail::set_function(std::forward<Function>(f), writer, name, false);
958}
959
965template<typename Function, typename Writer, GridFormat::Concepts::Scalar T>
966void set_point_function(Function&& f, Writer& writer, const std::string& name, const Precision<T>& prec) {
967 FunctionDetail::set_function(std::forward<Function>(f), writer, name, prec, false);
968}
969
975template<typename Writer, typename Function>
976void set_cell_function(Function&& f, Writer& writer, const std::string& name) {
977 FunctionDetail::set_function(std::forward<Function>(f), writer, name, true);
978}
979
985template<typename Writer, typename Function, GridFormat::Concepts::Scalar T>
986void set_cell_function(Function&& f, Writer& writer, const std::string& name, const Precision<T>& prec) {
987 FunctionDetail::set_function(std::forward<Function>(f), writer, name, prec, true);
988}
989
990} // namespace Dune
991} // namespace GridFormat
992
993#else // GRIDFORMAT_HAVE_DUNE_LOCALFUNCTIONS
994
995#ifndef DOXYGEN
996namespace GridFormat::Dune {
997
998template<typename... T>
999class LagrangePolynomialGrid {
1000 template<typename... Ts> struct False { static constexpr bool value = false; };
1001 public:
1002 template<typename... Args>
1003 LagrangePolynomialGrid(Args&&... args) {
1004 static_assert(False<Args...>::value, "Dune-localfunctions required for higher-order output");
1005 }
1006};
1007
1008} // namespace GridFormat::Dune
1009#endif // DOXYGEN
1010
1011#endif // GRIDFORMAT_HAVE_DUNE_LOCALFUNCTIONS
1012
1013namespace GridFormat::Dune {
1014
1015inline constexpr ::Dune::GeometryType to_dune_geometry_type(const CellType& ct) {
1016 namespace DGT = ::Dune::GeometryTypes;
1017 switch (ct) {
1018 case CellType::vertex: return DGT::vertex;
1019 case CellType::segment: return DGT::line;
1020 case CellType::triangle: return DGT::triangle;
1021 case CellType::pixel: return DGT::quadrilateral;
1022 case CellType::quadrilateral: return DGT::quadrilateral;
1023 case CellType::tetrahedron: return DGT::tetrahedron;
1024 case CellType::hexahedron: return DGT::hexahedron;
1025 case CellType::voxel: return DGT::hexahedron;
1026 case CellType::polygon: throw NotImplemented("No conversion from polygon to Dune::GeometryType");
1027 case CellType::lagrange_segment: throw NotImplemented("Cannot map higher-order cells to Dune::GeometryType");
1028 case CellType::lagrange_triangle: throw NotImplemented("Cannot map higher-order cells to Dune::GeometryType");
1029 case CellType::lagrange_quadrilateral: throw NotImplemented("Cannot map higher-order cells to Dune::GeometryType");
1030 case CellType::lagrange_tetrahedron: throw NotImplemented("Cannot map higher-order cells to Dune::GeometryType");
1031 case CellType::lagrange_hexahedron: throw NotImplemented("Cannot map higher-order cells to Dune::GeometryType");
1032 default: throw NotImplemented("Unknown cell type.");
1033 }
1034}
1035
1036template<std::integral TargetType, std::integral T>
1037auto to_dune(const CellType& ct, const std::vector<T>& corners) {
1038 auto gt = to_dune_geometry_type(ct);
1039 std::vector<TargetType> reordered(corners.size());
1040
1041 // voxels/pixels map to hexes/quads, but reordering has to be skipped
1042 if (ct != CellType::pixel && ct != CellType::voxel) {
1043 std::ranges::copy(
1044 std::views::iota(std::size_t{0}, corners.size())
1045 | std::views::transform([&] (std::size_t i) {
1046 return corners[GridFormat::Traits::DuneDetail::map_corner_index(gt, i)];
1047 }),
1048 reordered.begin()
1049 );
1050 } else {
1051 std::ranges::copy(corners, reordered.begin());
1052 }
1053
1054 return std::make_tuple(std::move(gt), std::move(reordered));
1055}
1056
1071template<typename Grid>
1073 public:
1074 static constexpr int space_dim = Grid::dimensionworld;
1075 using ctype = typename Grid::ctype;
1076 using DuneFactory = ::Dune::GridFactory<Grid>;
1077
1078 GridFactoryAdapter(DuneFactory& factory)
1079 : _factory{factory}
1080 {}
1081
1082 template<std::size_t _space_dim>
1083 void insert_point(const std::array<ctype, _space_dim>& point) {
1084 ::Dune::FieldVector<ctype, space_dim> p;
1085 std::copy_n(point.begin(), space_dim, p.begin());
1086 _factory.insertVertex(p);
1087 }
1088
1089 void insert_cell(const CellType& ct, const std::vector<std::size_t>& corners) {
1090 const auto [dune_gt, dune_corners] = to_dune<unsigned int>(ct, corners);
1091 _factory.insertElement(dune_gt, dune_corners);
1092 }
1093
1094 private:
1095 DuneFactory& _factory;
1096};
1097
1098} // namespace GridFormat::Dune
1099
1100#endif // GRIDFORMAT_TRAITS_DUNE_HPP_
Implements the field interface for a Dune::Function defined on a (wrapped) Dune::GridView.
Definition: dune.hpp:788
Adapter around a Dune::GridFactory to be compatible with GridFormat::Concepts::GridFactory....
Definition: dune.hpp:1072
Exposes a Dune::GridView as a grid composed of lagrange cells with the given order....
Definition: dune.hpp:509
Abstract interface for fields of values that is used by writers/readers to store fields.
Definition: field.hpp:37
Interface to the writers for all supported file formats. Depending on the chosen format,...
Definition: writer.hpp:90
Definition: dune.hpp:757
void set_function(const dolfinx::fem::Function< T > &f, Writer &writer, const std::string &name="", const Precision< P > &prec={})
Insert the given function into the writer as field.
Definition: dolfinx.hpp:378
Definition: dune.hpp:656