56 using Scalar =
typename GridView::ctype;
57 static constexpr int dim = GridView::dimension;
58 using GlobalPosition = Dune::FieldVector<Scalar, GridView::dimensionworld>;
70 template<
class DofMapper,
class Element,
class LocalKey,
class IdSet>
71 static std::size_t
dofIndex(
const DofMapper& m,
const Element& e,
72 const LocalKey& lk,
const IdSet& idSet)
74 const auto base = m.subIndex(e, lk.subEntity(), lk.codim());
75 const auto& ref = Dune::referenceElement<Scalar, dim>(e.type());
77 if (lk.codim() == 0 || lk.codim() == dim)
78 return base + lk.index();
80 if (lk.codim() == dim - 1)
82 const int rv0 = ref.subEntity(lk.subEntity(), dim-1, 0, dim);
83 const int rv1 = ref.subEntity(lk.subEntity(), dim-1, 1, dim);
84 const bool flip = idSet.subId(e, rv0, dim) > idSet.subId(e, rv1, dim);
85 return base + (flip ? 1 - (int)lk.index() : (
int)lk.index());
88 if constexpr (dim == 3)
92 if (ref.type(lk.subEntity(), 1).isTriangle())
93 return base + lk.index();
94 if (ref.type(lk.subEntity(), 1).isQuadrilateral())
96 const auto j = quadFaceOrientIdx_(e, lk.subEntity(), ref, idSet);
97 return base + quadFacePerm_[j][lk.index()];
102 return base + lk.index();
109 template<
class ElemDisc>
112 const auto& gridDisc = elemDisc.gridDiscretization();
114 return Dune::transformedRangeView(
115 Dune::range(elemDisc.numLocalDofs()),
117 return CVFE::LocalDof{
118 static_cast<LocalIndexType>(i),
119 static_cast<GridIndexType>(dofIndex(
120 gridDisc.dofMapper(),
122 elemDisc.feLocalCoefficients().localKey(i),
123 gridDisc.gridView().grid().globalIdSet())),
124 static_cast<GridIndexType>(elemDisc.elementIndex())
136 template<
class ElemDisc,
class BoundaryFace>
139 const auto& gridDisc = elemDisc.gridDiscretization();
141 return std::views::iota(std::size_t(0), elemDisc.numLocalDofs())
142 | std::views::filter([&](std::size_t i) {
144 elemDisc.element().type(),
145 boundaryFace.intersectionIndex(),
146 elemDisc.feLocalCoefficients().localKey(i));
148 | std::views::transform([&](std::size_t i) {
150 static_cast<LocalIndexType
>(i),
151 static_cast<GridIndexType
>(
dofIndex(
152 gridDisc.dofMapper(),
154 elemDisc.feLocalCoefficients().localKey(i),
155 gridDisc.gridView().grid().globalIdSet())),
156 static_cast<GridIndexType
>(elemDisc.elementIndex())
162 template<
class Geometry,
class LocalKey>
163 static GlobalPosition
dofPosition(
const Geometry& geo,
const LocalKey& lk)
164 {
return geo.global(localDofPos_(geo.type(), lk)); }
167 template<
class LocalKey>
168 static typename GridView::template Codim<0>::Entity::Geometry::LocalCoordinate
170 {
return localDofPos_(gt, lk); }
175 static constexpr std::array<std::array<unsigned char, 4>, 8> quadFacePerm_ = {{
176 {0,1,2,3}, {1,3,0,2}, {3,2,1,0}, {2,0,3,1},
177 {0,2,1,3}, {2,3,0,1}, {3,1,2,0}, {1,0,3,2},
182 template<
class Element,
class IdSet>
183 static unsigned int quadFaceOrientIdx_(
const Element& e,
unsigned int face,
184 const auto& ref,
const IdSet& idSet)
186 std::array<typename IdSet::IdType, 4> vg;
187 for (
int i = 0; i < 4; ++i)
188 vg[i] = idSet.subId(e, ref.subEntity(face, 1, i, dim), dim);
190 const auto flip = [&](
int ed) {
191 const int ei = ref.subEntity(face, 1, ed, dim-1);
192 return idSet.subId(e, ref.subEntity(ei, dim-1, 0, dim), dim)
193 > idSet.subId(e, ref.subEntity(ei, dim-1, 1, dim), dim);
195 const std::size_t eo = (std::size_t(flip(0))<<0) | (std::size_t(flip(1))<<1)
196 | (std::size_t(flip(2))<<2) | (std::size_t(flip(3))<<3);
198 constexpr uint32_t eoToImin = 0b11'11'01'01'11'00'00'00'10'00'00'01'10'00'10'00;
200 if (eo == 5) i_min = (vg[1] < vg[2]) ? 1 : 2;
201 else if (eo == 10) i_min = (vg[0] < vg[3]) ? 0 : 3;
202 else i_min = (eoToImin >> (2*eo)) & 3;
204 if (i_min == 0)
return 0
u | (unsigned(vg[2] < vg[1]) << 2);
205 if (i_min == 1)
return 3u | (unsigned(vg[0] < vg[3]) << 2);
206 if (i_min == 2)
return 1u | (unsigned(vg[3] < vg[0]) << 2);
207 return 2u | (unsigned(vg[1] < vg[2]) << 2);
210 template<
class LocalKey>
211 static typename GridView::template Codim<0>::Entity::Geometry::LocalCoordinate
212 localDofPos_(Dune::GeometryType gt,
const LocalKey& lk)
214 using LocalCoord =
typename GridView::template Codim<0>::Entity::Geometry::LocalCoordinate;
215 const auto ref = Dune::referenceElement<Scalar, dim>(gt);
217 if (lk.codim() == dim)
218 return ref.position(lk.subEntity(), dim);
220 if (lk.codim() == dim - 1)
222 const int v0 = ref.subEntity(lk.subEntity(), dim-1, 0, dim);
223 const int v1 = ref.subEntity(lk.subEntity(), dim-1, 1, dim);
224 auto pos = LocalCoord(ref.position(v0, dim));
225 const auto dir = LocalCoord(ref.position(v1, dim)) - pos;
226 pos.axpy(Scalar(lk.index() + 1) / Scalar(3), dir);
230 if constexpr (dim == 3)
234 const auto faceGeom = ref.template geometry<1>(lk.subEntity());
237 const Dune::FieldVector<Scalar, 2> c{Scalar(1)/3, Scalar(1)/3};
238 return faceGeom.global(c);
242 const auto ix = lk.index() % 2, iy = lk.index() / 2;
243 const Dune::FieldVector<Scalar, 2> c{Scalar(ix+1)/3, Scalar(iy+1)/3};
244 return faceGeom.global(c);
252 return ref.position(0, 0);
254 if constexpr (dim == 2)
256 const auto ix = lk.index() % 2, iy = lk.index() / 2;
257 return LocalCoord{Scalar(ix+1)/3, Scalar(iy+1)/3};
259 else if constexpr (dim == 3)
261 const auto ix = lk.index()%2, iy = (lk.index()/2)%2, iz = lk.index()/4;
262 return LocalCoord{Scalar(ix+1)/3, Scalar(iy+1)/3, Scalar(iz+1)/3};
266 DUNE_THROW(Dune::NotImplemented,
"PQ3 local DOF position for codim=" << lk.codim());