8#ifndef GRIDFORMAT_TRAITS_DUNE_HPP_
9#define GRIDFORMAT_TRAITS_DUNE_HPP_
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"
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
40#include <gridformat/common/ranges.hpp>
41#include <gridformat/common/exceptions.hpp>
42#include <gridformat/common/type_traits.hpp>
44#include <gridformat/grid/cell_type.hpp>
45#include <gridformat/grid/traits.hpp>
47namespace GridFormat::Traits {
49template<
typename T,
int R,
int C>
50struct StaticSize<Dune::FieldMatrix<T, R, C>> {
51 static constexpr std::size_t value = R;
57 inline int map_corner_index(
const Dune::GeometryType& gt,
int i) {
58 if (gt.isQuadrilateral()) {
60 static constexpr int map[4] = {0, 1, 3, 2};
63 if (gt.isHexahedron()) {
65 static constexpr int map[8] = {0, 1, 3, 2, 4, 5, 7, 6};
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");
81 template<
typename Gr
idView>
82 using Element =
typename GridView::template Codim<0>::Entity;
84 template<
typename Gr
idView>
85 using Vertex =
typename GridView::template Codim<GridView::dimension>::Entity;
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>()
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>()
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))
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))
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);
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));
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());
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();
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);
181namespace DuneDetail {
184 struct IsDuneYaspGrid :
public std::false_type {};
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<
190 Dune::TensorProductCoordinates<typename Coords::ctype, dim>
194 template<
typename Gr
idView>
195 inline constexpr bool is_yasp_grid_view = IsDuneYaspGrid<typename GridView::Grid>::value;
197 template<
typename Gr
idView>
requires(is_yasp_grid_view<GridView>)
198 inline constexpr bool uses_tensor_product_coords = IsDuneYaspGrid<typename GridView::Grid>::uses_tp_coords;
200 template<
typename ctype,
int dim>
201 auto spacing_in(
int direction,
const Dune::EquidistantCoordinates<ctype, dim>& coords) {
202 return coords.meshsize(direction, 0);
204 template<
typename ctype,
int dim>
205 auto spacing_in(
int direction,
const Dune::EquidistantOffsetCoordinates<ctype, dim>& coords) {
206 return coords.meshsize(direction, 0);
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();
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;
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();
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);
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();
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));
259template<
typename Traits>
260 requires(DuneDetail::is_yasp_grid_view<Dune::GridView<Traits>> and
261 !DuneDetail::uses_tensor_product_coords<Dune::GridView<Traits>>)
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);
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);
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();
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);
294#if GRIDFORMAT_HAVE_DUNE_LOCALFUNCTIONS
301#include <type_traits>
302#include <unordered_map>
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"
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
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>
325namespace GridFormat {
329namespace DUNE = Dune;
334namespace LagrangeDetail {
336 inline int dune_to_gfmt_sub_entity(
const DUNE::GeometryType& gt,
int i,
int codim) {
337 if (gt.isTriangle()) {
340 static constexpr int map[3] = {0, 2, 1};
344 if (gt.isQuadrilateral()) {
347 static constexpr int map[4] = {0, 1, 3, 2};
352 static constexpr int map[4] = {3, 1, 0, 2};
356 if (gt.isTetrahedron()) {
359 static constexpr int map[6] = {0, 2, 1, 3, 4, 5};
364 static constexpr int map[4] = {3, 0, 2, 1};
368 if (gt.isHexahedron()) {
371 static constexpr int map[8] = {0, 1, 3, 2, 4, 5, 7, 6};
376 static constexpr int map[12] = {8, 9, 11, 10, 3, 1, 0, 2, 7, 5, 4, 6};
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");
393 template<
typename Gr
idView>
396 static constexpr std::size_t reserved_size = 64;
399 using PointSet = DUNE::EquidistantPointSet<typename GridView::ctype, GridView::dimension>;
400 using Point =
typename PointSet::LagrangePoint;
402 explicit LocalPoints(
unsigned int order)
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);
413 std::size_t size()
const {
414 return _points.size();
417 const Point& at(std::size_t i)
const {
418 return _points[_sorted_indices.at(i)];
421 std::ranges::range
auto get()
const {
422 return _sorted_indices | std::views::transform([&] (
unsigned int i) {
428 void _setup_sorted_indices(
const DUNE::GeometryType& geo_type) {
430 std::views::iota(
unsigned{0},
static_cast<unsigned int>(_points.size())),
431 std::back_inserter(_sorted_indices)
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;
442 return _points[i1].localKey().codim() > _points[i2].localKey().codim();
447 ReservedVector<unsigned int, reserved_size> _sorted_indices;
452 template<
typename Gr
idView>
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));
461 std::size_t global_index;
462 unsigned int sub_index;
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)
469 return entity_dofs[key.sub_index] != -1;
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);
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];
483 return static_cast<std::size_t
>(index);
487 _codim_to_global_indices.clear();
493 ReservedVector<std::int64_t, 20>
495 > _codim_to_global_indices;
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;
515 using LocalPoints = LagrangeDetail::LocalPoints<GV>;
516 using Mapper = DUNE::MultipleCodimMultipleGeomTypeMapper<GV>;
517 static constexpr int dim = GV::dimension;
519 template<
typename Coord>
525 using _GlobalPoint = P<GlobalCoordinate>;
526 using _LocalPoint = P<LocalCoordinate>;
530 using Position = GlobalCoordinate;
531 using Cell = Element;
532 using Point = _GlobalPoint;
533 using LocalPoint = _LocalPoint;
536 : _grid_view{grid_view}
539 throw InvalidState(
"Order must be >= 1");
543 void update(
const GridView& grid_view) {
545 _grid_view = grid_view;
546 _make_codim_mappers();
547 _update_local_points();
552 _codim_to_mapper.clear();
553 _local_points.clear();
558 std::size_t number_of_cells()
const {
559 return _cells.empty() ? 0 : Traits::NumberOfCells<GridView>::get(_grid_view);
562 std::size_t number_of_points()
const {
563 return _points.size();
566 std::size_t number_of_points(
const Element& element)
const {
567 return _local_points.at(element.type()).size();
570 std::ranges::range
auto cells()
const {
571 return Traits::Cells<GridView>::get(_grid_view);
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]};
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) {
587 .coordinates = _points[corners[i]]
592 const GridView& grid_view()
const {
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);
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>{})});
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()
631 .sub_index = localKey.index()
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()));
639 _cells[element_index].push_back(point_mapper.get(key));
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;
658 static const auto& get(
const GV& gv) {
667 return grid.grid_view();
677template<
typename Gr
idView>
678struct Points<Dune::LagrangePolynomialGrid<GridView>> {
680 return mesh.points();
684template<
typename Gr
idView>
685struct Cells<Dune::LagrangePolynomialGrid<GridView>> {
691template<
typename Gr
idView>
692struct NumberOfPoints<Dune::LagrangePolynomialGrid<GridView>> {
694 return mesh.number_of_points();
698template<
typename Gr
idView>
699struct NumberOfCells<Dune::LagrangePolynomialGrid<GridView>> {
701 return mesh.number_of_cells();
705template<
typename Gr
idView>
706struct NumberOfCellPoints<Dune::LagrangePolynomialGrid<GridView>,
709 const typename Dune::LagrangePolynomialGrid<GridView>::Cell& cell) {
710 return mesh.number_of_points(cell);
714template<
typename Gr
idView>
715struct CellPoints<Dune::LagrangePolynomialGrid<GridView>,
718 const typename Dune::LagrangePolynomialGrid<GridView>::Cell& cell) {
719 return mesh.points(cell);
723template<
typename Gr
idView>
724struct CellType<Dune::LagrangePolynomialGrid<GridView>,
727 const typename Dune::LagrangePolynomialGrid<GridView>::Cell& cell) {
728 return Dune::LagrangeDetail::cell_type(cell.type());
732template<
typename Gr
idView>
733struct PointCoordinates<Dune::LagrangePolynomialGrid<GridView>,
736 const typename Dune::LagrangePolynomialGrid<GridView>::Point& point) {
737 return point.coordinates;
741template<
typename Gr
idView>
742struct PointId<Dune::LagrangePolynomialGrid<GridView>,
745 const typename Dune::LagrangePolynomialGrid<GridView>::Point& point) {
756template<
typename T,
typename Gr
idView>
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()) };
766namespace FunctionDetail {
768 template<
typename Function,
typename Gr
idView>
769 using RangeType = std::invoke_result_t<
770 typename std::remove_cvref_t<Function>::LocalFunction,
771 typename GridView::template Codim<0>::Entity::Geometry::LocalCoordinate
774 template<
typename Function,
typename Gr
idView>
775 using RangeScalar = FieldScalar<RangeType<Function, GridView>>;
786template<
typename _Function,
typename Gr
id, Gr
idFormat::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;
794 static constexpr bool is_higher_order = std::is_same_v<Grid, LagrangePolynomialGrid<GridView>>;
798 requires(std::is_same_v<std::remove_cvref_t<F>, Function>)
801 const Precision<T>& = {},
802 bool cellwise_constant =
false)
803 : _function{std::forward<F>(function)}
805 , _cellwise_constant{cellwise_constant} {
806 if constexpr (
requires { function.basis(); }) {
807 static_assert(std::is_same_v<typename Function::Basis::GridView, GridView>);
809 throw ValueError(
"Function and mesh do not use the same underlying grid");
814 MDLayout _layout()
const override {
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>>();
821 DynamicPrecision _precision()
const override {
822 return {Precision<T>{}};
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);
830 Serialization result(num_entries*
sizeof(T));
831 auto out_data = result.template as_span_of<T>();
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);
845 _fill_point_values(out_data, num_entries_per_value);
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;
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);
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);
874 handled[running_idx] =
true;
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);
894 handled[point.index] =
true;
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);
906 template<Gr
idFormat::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);
913 bool _cellwise_constant;
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
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>;
929template<
typename T>
struct IsLagrangeGrid :
public std::false_type {};
930template<
typename GV>
struct IsLagrangeGrid<LagrangePolynomialGrid<GV>> :
public std::true_type {};
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) {
936 w.set_cell_field(name, FunctionField{std::forward<F>(f), w.grid(), prec,
true});
938 w.set_point_field(name, FunctionField{std::forward<F>(f), w.grid(), prec,
false});
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);
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);
965template<
typename Function,
typename Writer, Gr
idFormat::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);
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);
985template<
typename Writer,
typename Function, Gr
idFormat::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);
996namespace GridFormat::Dune {
998template<
typename... T>
999class LagrangePolynomialGrid {
1000 template<
typename... Ts>
struct False {
static constexpr bool value =
false; };
1002 template<
typename... Args>
1003 LagrangePolynomialGrid(Args&&... args) {
1004 static_assert(False<Args...>::value,
"Dune-localfunctions required for higher-order output");
1013namespace GridFormat::Dune {
1015inline constexpr ::Dune::GeometryType to_dune_geometry_type(
const CellType& ct) {
1016 namespace DGT = ::Dune::GeometryTypes;
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.");
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());
1042 if (ct != CellType::pixel && ct != CellType::voxel) {
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)];
1051 std::ranges::copy(corners, reordered.begin());
1054 return std::make_tuple(std::move(gt), std::move(reordered));
1071template<
typename Gr
id>
1074 static constexpr int space_dim = Grid::dimensionworld;
1075 using ctype =
typename Grid::ctype;
1076 using DuneFactory = ::Dune::GridFactory<Grid>;
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);
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);
1095 DuneFactory& _factory;
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