version 3.11-dev
Loading...
Searching...
No Matches
cvfelagrangegrid.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
35#ifndef DUMUX_IO_CVFE_LAGRANGE_GRID_HH
36#define DUMUX_IO_CVFE_LAGRANGE_GRID_HH
37
38#include <config.h>
39
40#if DUMUX_HAVE_GRIDFORMAT
41
42#include <algorithm>
43#include <array>
44#include <ranges>
45#include <tuple>
46#include <vector>
47
48#include <gridformat/traits/dune.hpp>
49#include <gridformat/grid/traits.hpp>
50#include <gridformat/grid/cell_type.hpp>
51
52#include <dune/geometry/referenceelements.hh>
53#include <dune/grid/common/mcmgmapper.hh>
54#include <dune/localfunctions/lagrange/lagrangelfecache.hh>
55
58
59namespace Dumux::IO {
60
61#ifndef DOXYGEN
62namespace CVFELagrangeDetail {
63
64// Compute the VTK-ordering sort key for a DOF given its LocalKey.
65// Primary sort: highest codim first (corners before edges before faces before interior).
66// Secondary: VTK sub-entity slot (from dune_to_gfmt_sub_entity).
67// Tertiary: within-slot index, reversed for triangle edge subEntity 1.
68//
69// Triangle edge subEntity 1 (x=0, Dune direction v0→v2) maps to VTK slot 2 which
70// traverses in the opposite direction (v2→v0). Negating key.index() makes larger
71// indices sort first, placing the DOF closer to v2 before the DOF closer to v0.
72inline std::tuple<int, int, int> vtkSortKey(const Dune::GeometryType& gt, const auto& key)
73{
74 using namespace GridFormat::Dune::LagrangeDetail;
75 const int codim = key.codim();
76 const int vtkSub = dune_to_gfmt_sub_entity(gt, key.subEntity(), codim);
77 const bool rev = gt.isTriangle() && codim == 1 && key.subEntity() == 1;
78 const int within = rev ? -(int(key.index())) : int(key.index());
79 return {-codim, vtkSub, within};
80}
81
82// Compile-time list mapping polynomial order k to the appropriate DOF helper.
83// PQ2LagrangeDofHelper and PQ3LagrangeDofHelper are defined in their respective
84// discretization headers and provide the uniform 4-argument dofIndex interface.
85template<int k, class GridView>
86using PQkDofHelpers = std::conditional_t<k == 2,
87 Dumux::PQ2LagrangeDofHelper<GridView>,
88 Dumux::PQ3LagrangeDofHelper<GridView>>;
89
90// Lagrange DOF mapper layout: number of interior Lagrange DOFs per geometry type.
91// For a simplex of dimension d: binom(k-1, d); for a cube: (k-1)^d.
92template<int k>
93int lagrangeLayout(Dune::GeometryType gt, int /*gridDim*/)
94{
95 const int d = gt.dim();
96 if (gt.isCube())
97 {
98 int r = 1;
99 for (int i = 0; i < d; ++i) r *= k - 1;
100 return r;
101 }
102 if (gt.isSimplex())
103 {
104 if (k - 1 < d) return 0;
105 int r = 1;
106 for (int i = 0; i < d; ++i) r = r * (k - 1 - i) / (i + 1);
107 return r;
108 }
109 DUNE_THROW(Dune::NotImplemented, "Lagrange layout for geometry type " << gt);
110}
111
112} // namespace CVFELagrangeDetail
113#endif // DOXYGEN
114
115
128template<class GV, int k>
129class CVFELagrangeGrid
130{
131 static_assert(k >= 2, "CVFELagrangeGrid requires k >= 2");
132
133 using Element = typename GV::template Codim<0>::Entity;
134 using ElementGeometry = typename Element::Geometry;
135 using GlobalCoordinate = typename ElementGeometry::GlobalCoordinate;
136 using Scalar = typename GV::ctype;
137 static constexpr int dim = GV::dimension;
138
139 using DofMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
140 using FECache = Dune::LagrangeLocalFiniteElementCache<Scalar, Scalar, dim, k>;
141 using GeomHelper = CVFELagrangeDetail::PQkDofHelpers<k, GV>;
142
143 struct PointData {
144 std::size_t index;
145 std::size_t dofIndex;
146 GlobalCoordinate coordinates;
147 };
148
149public:
150 using GridView = GV;
151 using Cell = Element;
152 using Point = PointData;
153 using Position = GlobalCoordinate;
154
155 explicit CVFELagrangeGrid(const GV& gv)
156 : gridView_{gv}
157 , dofMapper_{gv, CVFELagrangeDetail::lagrangeLayout<k>}
158 { build_(); }
159
160 void update(const GV& gv)
161 {
162 gridView_ = gv;
163 dofMapper_.update(gv);
164 build_();
165 }
166
167 const GV& gridView() const { return gridView_; }
168
169 std::size_t numberOfPoints() const { return usedDofs_.size(); }
170 std::size_t numberOfCells() const { return numCells_; }
171
172 std::size_t numberOfCellPoints(const Element& e) const
173 { return feCache_.get(e.type()).localCoefficients().size(); }
174
175 auto points() const
176 {
177 return std::views::iota(std::size_t{0}, usedDofs_.size())
178 | std::views::transform([this](std::size_t vtkIdx) {
179 const auto dofIdx = usedDofs_[vtkIdx];
180 return Point{vtkIdx, dofIdx, positions_[dofIdx]};
181 });
182 }
183
184 auto cells() const
185 { return GridFormat::Traits::Cells<GV>::get(gridView_); }
186
187 auto points(const Element& e) const
188 {
189 const auto eIdx = gridView_.indexSet().index(e);
190 const std::size_t n = connectivity_[eIdx].size();
191 return std::views::iota(std::size_t{0}, n)
192 | std::views::transform([this, eIdx](std::size_t vtk) {
193 const auto vtkIdx = connectivity_[eIdx][vtk];
194 const auto dofIdx = usedDofs_[vtkIdx];
195 return Point{vtkIdx, dofIdx, positions_[dofIdx]};
196 });
197 }
198
199private:
200 void build_()
201 {
202 const auto& gv = gridView_;
203 const std::size_t numAllDofs = dofMapper_.size();
204
205 positions_.assign(numAllDofs, GlobalCoordinate{});
206 connectivity_.assign(gv.size(0), {});
207 numCells_ = 0;
208
209 std::vector<bool> used(numAllDofs, false);
210 const auto& idSet = gv.grid().globalIdSet();
211
212 for (const auto& element : GridFormat::Traits::Cells<GV>::get(gv))
213 {
214 ++numCells_;
215 const auto eIdx = gv.indexSet().index(element);
216 const auto geo = element.geometry();
217 const auto gt = element.type();
218 const auto& lc = feCache_.get(gt).localCoefficients();
219 const int n = static_cast<int>(lc.size());
220
221 std::vector<std::pair<std::tuple<int,int,int>, int>> sortable(n);
222 for (int i = 0; i < n; ++i)
223 sortable[i] = {CVFELagrangeDetail::vtkSortKey(gt, lc.localKey(i)), i};
224 std::sort(sortable.begin(), sortable.end());
225
226 connectivity_[eIdx].resize(n);
227 for (int vtk = 0; vtk < n; ++vtk)
228 {
229 const int i = sortable[vtk].second;
230 const auto& lk = lc.localKey(i);
231 const auto g = GeomHelper::dofIndex(dofMapper_, element, lk, idSet);
232 connectivity_[eIdx][vtk] = g;
233 positions_[g] = GeomHelper::dofPosition(geo, lk);
234 used[g] = true;
235 }
236 }
237
238 vtk_of_dof_.assign(numAllDofs, std::size_t(-1));
239 usedDofs_.clear();
240 usedDofs_.reserve(numAllDofs);
241 for (std::size_t g = 0; g < numAllDofs; ++g)
242 if (used[g]) { vtk_of_dof_[g] = usedDofs_.size(); usedDofs_.push_back(g); }
243
244 for (auto& conn : connectivity_)
245 for (auto& idx : conn)
246 idx = vtk_of_dof_[idx];
247 }
248
249 GV gridView_;
250 DofMapper dofMapper_;
251 FECache feCache_;
252 std::size_t numCells_{0};
253 std::vector<GlobalCoordinate> positions_;
254 std::vector<std::vector<std::size_t>> connectivity_;
255 std::vector<std::size_t> usedDofs_;
256 std::vector<std::size_t> vtk_of_dof_;
257};
258
259
260} // namespace Dumux::IO
261
262
263namespace GridFormat::Traits {
264
265// Traits for CVFELagrangeGrid<GV, k>
266template<class GV, int k>
267struct Points<Dumux::IO::CVFELagrangeGrid<GV, k>> {
268 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid)
269 { return grid.points(); }
270};
271
272template<class GV, int k>
273struct Cells<Dumux::IO::CVFELagrangeGrid<GV, k>> {
274 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid)
275 { return grid.cells(); }
276};
277
278template<class GV, int k>
279struct NumberOfPoints<Dumux::IO::CVFELagrangeGrid<GV, k>> {
280 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid)
281 { return grid.numberOfPoints(); }
282};
283
284template<class GV, int k>
285struct NumberOfCells<Dumux::IO::CVFELagrangeGrid<GV, k>> {
286 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid)
287 { return grid.numberOfCells(); }
288};
289
290template<class GV, int k>
291struct NumberOfCellPoints<Dumux::IO::CVFELagrangeGrid<GV, k>,
292 typename Dumux::IO::CVFELagrangeGrid<GV, k>::Cell> {
293 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid,
294 const typename Dumux::IO::CVFELagrangeGrid<GV, k>::Cell& cell)
295 { return grid.numberOfCellPoints(cell); }
296};
297
298template<class GV, int k>
299struct CellPoints<Dumux::IO::CVFELagrangeGrid<GV, k>,
300 typename Dumux::IO::CVFELagrangeGrid<GV, k>::Cell> {
301 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid,
302 const typename Dumux::IO::CVFELagrangeGrid<GV, k>::Cell& cell)
303 { return grid.points(cell); }
304};
305
306template<class GV, int k>
307struct CellType<Dumux::IO::CVFELagrangeGrid<GV, k>,
308 typename Dumux::IO::CVFELagrangeGrid<GV, k>::Cell> {
309 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>&,
310 const typename Dumux::IO::CVFELagrangeGrid<GV, k>::Cell& cell)
311 { return GridFormat::Dune::LagrangeDetail::cell_type(cell.type()); }
312};
313
314template<class GV, int k>
315struct PointCoordinates<Dumux::IO::CVFELagrangeGrid<GV, k>,
316 typename Dumux::IO::CVFELagrangeGrid<GV, k>::Point> {
317 static const auto& get(const Dumux::IO::CVFELagrangeGrid<GV, k>&,
318 const typename Dumux::IO::CVFELagrangeGrid<GV, k>::Point& point)
319 { return point.coordinates; }
320};
321
322template<class GV, int k>
323struct PointId<Dumux::IO::CVFELagrangeGrid<GV, k>,
324 typename Dumux::IO::CVFELagrangeGrid<GV, k>::Point> {
325 static auto get(const Dumux::IO::CVFELagrangeGrid<GV, k>&,
326 const typename Dumux::IO::CVFELagrangeGrid<GV, k>::Point& point)
327 { return point.index; }
328};
329
330} // namespace GridFormat::Traits
331
332
333namespace GridFormat::Dune::Traits {
334
335// Expose the underlying GridView so gridformat's Dune::Functions integration
336// (set_point_function) can bind local functions to elements.
337template<class GV, int k>
338struct GridView<Dumux::IO::CVFELagrangeGrid<GV, k>> {
339 using type = GV;
340 static const auto& get(const Dumux::IO::CVFELagrangeGrid<GV, k>& grid)
341 { return grid.gridView(); }
342};
343
344} // namespace GridFormat::Dune::Traits
345
346#endif // DUMUX_HAVE_GRIDFORMAT
347
348#endif
@ element
Definition fieldtype.hh:23
Definition cvfegridfunction.hh:31
Lightweight DOF helper for order-2 Lagrange elements.
Lightweight DOF helper for order-3 Lagrange elements.